diff options
Diffstat (limited to 'servers')
190 files changed, 18793 insertions, 11937 deletions
diff --git a/servers/SCsub b/servers/SCsub index 121990f2e1..76c11724d3 100644 --- a/servers/SCsub +++ b/servers/SCsub @@ -11,6 +11,7 @@ SConscript("physics_3d/SCsub") SConscript("physics_2d/SCsub") SConscript("rendering/SCsub") SConscript("audio/SCsub") +SConscript("text/SCsub") lib = env.add_library("servers", env.servers_sources) diff --git a/servers/audio/audio_driver_dummy.cpp b/servers/audio/audio_driver_dummy.cpp index a28dcb1015..47799dce96 100644 --- a/servers/audio/audio_driver_dummy.cpp +++ b/servers/audio/audio_driver_dummy.cpp @@ -46,7 +46,7 @@ Error AudioDriverDummy::init() { int latency = GLOBAL_GET("audio/driver/output_latency"); buffer_frames = closest_power_of_2(latency * mix_rate / 1000); - samples_in = memnew_arr(int32_t, buffer_frames * channels); + samples_in = memnew_arr(int32_t, (size_t)buffer_frames * channels); thread.start(AudioDriverDummy::thread_func, this); diff --git a/servers/audio/audio_filter_sw.cpp b/servers/audio/audio_filter_sw.cpp index bcfa4c4c37..b31014bd21 100644 --- a/servers/audio/audio_filter_sw.cpp +++ b/servers/audio/audio_filter_sw.cpp @@ -173,28 +173,20 @@ void AudioFilterSW::prepare_coefficients(Coeffs *p_coeffs) { p_coeffs->a2 = ((tmpgain + 1.0) - (tmpgain - 1.0) * cos_v - beta * sin_v); } break; - }; + } p_coeffs->b0 /= a0; p_coeffs->b1 /= a0; p_coeffs->b2 /= a0; p_coeffs->a1 /= 0.0 - a0; p_coeffs->a2 /= 0.0 - a0; - - //undenormalise - /* p_coeffs->b0=undenormalise(p_coeffs->b0); - p_coeffs->b1=undenormalise(p_coeffs->b1); - p_coeffs->b2=undenormalise(p_coeffs->b2); - p_coeffs->a1=undenormalise(p_coeffs->a1); - p_coeffs->a2=undenormalise(p_coeffs->a2);*/ } -void AudioFilterSW::set_stages(int p_stages) { //adjust for multiple stages - +void AudioFilterSW::set_stages(int p_stages) { stages = p_stages; } -/* Fouriertransform kernel to obtain response */ +/* Fourier transform kernel to obtain response */ float AudioFilterSW::get_response(float p_freq, Coeffs *p_coeffs) { float freq = p_freq / sampling_rate * Math_TAU; diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index 3c8a1469cd..d9c442facf 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -176,8 +176,9 @@ Error AudioRBResampler::setup(int p_channels, int p_src_mix_rate, int p_target_m rb_bits = desired_rb_bits; rb_len = (1 << rb_bits); rb_mask = rb_len - 1; - rb = memnew_arr(float, rb_len *p_channels); - read_buf = memnew_arr(float, rb_len *p_channels); + const size_t array_size = rb_len * (size_t)p_channels; + rb = memnew_arr(float, array_size); + read_buf = memnew_arr(float, array_size); } src_mix_rate = p_src_mix_rate; diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index e1b391b823..c098a97906 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -189,11 +189,21 @@ float AudioStream::get_length() const { return 0; } +bool AudioStream::is_monophonic() const { + bool ret; + if (GDVIRTUAL_CALL(_is_monophonic, ret)) { + return ret; + } + return true; +} + void AudioStream::_bind_methods() { ClassDB::bind_method(D_METHOD("get_length"), &AudioStream::get_length); + ClassDB::bind_method(D_METHOD("is_monophonic"), &AudioStream::is_monophonic); GDVIRTUAL_BIND(_instance_playback); GDVIRTUAL_BIND(_get_stream_name); GDVIRTUAL_BIND(_get_length); + GDVIRTUAL_BIND(_is_monophonic); } //////////////////////////////// @@ -221,6 +231,10 @@ float AudioStreamMicrophone::get_length() const { return 0; } +bool AudioStreamMicrophone::is_monophonic() const { + return true; +} + void AudioStreamMicrophone::_bind_methods() { } @@ -388,6 +402,14 @@ float AudioStreamRandomPitch::get_length() const { return 0; } +bool AudioStreamRandomPitch::is_monophonic() const { + if (audio_stream.is_valid()) { + return audio_stream->is_monophonic(); + } + + return true; // It doesn't really matter what we return here, but no sense instancing a many playbacks of a null stream. +} + void AudioStreamRandomPitch::_bind_methods() { ClassDB::bind_method(D_METHOD("set_audio_stream", "stream"), &AudioStreamRandomPitch::set_audio_stream); ClassDB::bind_method(D_METHOD("get_audio_stream"), &AudioStreamRandomPitch::get_audio_stream); diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 922335508e..12d4343f5c 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -102,12 +102,14 @@ protected: GDVIRTUAL0RC(Ref<AudioStreamPlayback>, _instance_playback) GDVIRTUAL0RC(String, _get_stream_name) GDVIRTUAL0RC(float, _get_length) + GDVIRTUAL0RC(bool, _is_monophonic) public: virtual Ref<AudioStreamPlayback> instance_playback(); virtual String get_stream_name() const; virtual float get_length() const; + virtual bool is_monophonic() const; }; // Microphone @@ -129,6 +131,8 @@ public: virtual float get_length() const override; //if supported, otherwise return 0 + virtual bool is_monophonic() const override; + AudioStreamMicrophone(); }; @@ -187,6 +191,7 @@ public: virtual String get_stream_name() const override; virtual float get_length() const override; //if supported, otherwise return 0 + virtual bool is_monophonic() const override; AudioStreamRandomPitch(); }; diff --git a/servers/audio/effects/audio_effect_capture.h b/servers/audio/effects/audio_effect_capture.h index 7f50fc4965..bb1d03be8c 100644 --- a/servers/audio/effects/audio_effect_capture.h +++ b/servers/audio/effects/audio_effect_capture.h @@ -34,6 +34,7 @@ #include "core/config/engine.h" #include "core/math/audio_frame.h" #include "core/object/ref_counted.h" +#include "core/templates/ring_buffer.h" #include "core/templates/vector.h" #include "servers/audio/audio_effect.h" #include "servers/audio_server.h" diff --git a/servers/audio/effects/audio_effect_limiter.h b/servers/audio/effects/audio_effect_limiter.h index d5def670a4..398613aa44 100644 --- a/servers/audio/effects/audio_effect_limiter.h +++ b/servers/audio/effects/audio_effect_limiter.h @@ -72,8 +72,6 @@ public: float get_soft_clip_ratio() const; Ref<AudioEffectInstance> instantiate() override; - void set_volume_db(float p_volume); - float get_volume_db() const; AudioEffectLimiter(); }; diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h index 1a89821f80..6e862b1377 100644 --- a/servers/audio/effects/audio_effect_record.h +++ b/servers/audio/effects/audio_effect_record.h @@ -93,7 +93,6 @@ class AudioEffectRecord : public AudioEffect { protected: static void _bind_methods(); - static void debug(uint64_t time_diff, int p_frame_count); public: Ref<AudioEffectInstance> instantiate() override; diff --git a/servers/audio/effects/audio_effect_reverb.h b/servers/audio/effects/audio_effect_reverb.h index d01d1120bd..eaa66352f6 100644 --- a/servers/audio/effects/audio_effect_reverb.h +++ b/servers/audio/effects/audio_effect_reverb.h @@ -90,8 +90,6 @@ public: float get_hpf() const; Ref<AudioEffectInstance> instantiate() override; - void set_volume_db(float p_volume); - float get_volume_db() const; AudioEffectReverb(); }; diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp index edb5c6d2dd..447acf53a4 100644 --- a/servers/audio/effects/audio_stream_generator.cpp +++ b/servers/audio/effects/audio_stream_generator.cpp @@ -64,6 +64,10 @@ float AudioStreamGenerator::get_length() const { return 0; } +bool AudioStreamGenerator::is_monophonic() const { + return true; +} + void AudioStreamGenerator::_bind_methods() { ClassDB::bind_method(D_METHOD("set_mix_rate", "hz"), &AudioStreamGenerator::set_mix_rate); ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamGenerator::get_mix_rate); diff --git a/servers/audio/effects/audio_stream_generator.h b/servers/audio/effects/audio_stream_generator.h index 6bec744081..918589f6d0 100644 --- a/servers/audio/effects/audio_stream_generator.h +++ b/servers/audio/effects/audio_stream_generator.h @@ -54,6 +54,7 @@ public: virtual String get_stream_name() const override; virtual float get_length() const override; + virtual bool is_monophonic() const override; AudioStreamGenerator(); }; diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 81735d522f..f7c8f0921c 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -196,6 +196,7 @@ int AudioDriverManager::get_driver_count() { void AudioDriverManager::initialize(int p_driver) { GLOBAL_DEF_RST("audio/driver/enable_input", false); GLOBAL_DEF_RST("audio/driver/mix_rate", DEFAULT_MIX_RATE); + GLOBAL_DEF_RST("audio/driver/mix_rate.web", 0); // Safer default output_latency for web (use browser default). GLOBAL_DEF_RST("audio/driver/output_latency", DEFAULT_OUTPUT_LATENCY); GLOBAL_DEF_RST("audio/driver/output_latency.web", 50); // Safer default output_latency for web. @@ -363,10 +364,10 @@ void AudioServer::_mix_step() { if (mixed_frames != buffer_size) { // We know we have at least the size of our lookahead buffer for fade-out purposes. - float fadeout_base = 0.87; + float fadeout_base = 0.94; float fadeout_coefficient = 1; - static_assert(LOOKAHEAD_BUFFER_SIZE == 32, "Update fadeout_base and comment here if you change LOOKAHEAD_BUFFER_SIZE."); - // 0.87 ^ 32 = 0.0116. There might still be a pop but it'll be way better than if we didn't do this. + static_assert(LOOKAHEAD_BUFFER_SIZE == 64, "Update fadeout_base and comment here if you change LOOKAHEAD_BUFFER_SIZE."); + // 0.94 ^ 64 = 0.01906. There might still be a pop but it'll be way better than if we didn't do this. for (unsigned int idx = mixed_frames; idx < buffer_size; idx++) { fadeout_coefficient *= fadeout_base; buf[idx] *= fadeout_coefficient; @@ -381,29 +382,24 @@ void AudioServer::_mix_step() { } } - ERR_FAIL_COND(playback->bus_details.load() == nullptr); + AudioStreamPlaybackBusDetails *ptr = playback->bus_details.load(); + ERR_FAIL_COND(ptr == nullptr); // By putting null into the bus details pointers, we're taking ownership of their memory for the duration of this mix. - AudioStreamPlaybackBusDetails *bus_details = nullptr; - { - std::atomic<AudioStreamPlaybackBusDetails *> bus_details_atomic = nullptr; - bus_details = playback->bus_details.exchange(bus_details_atomic); - } - ERR_FAIL_COND(bus_details == nullptr); - AudioStreamPlaybackBusDetails *prev_bus_details = playback->prev_bus_details; + AudioStreamPlaybackBusDetails bus_details = *ptr; // Mix to any active buses. for (int idx = 0; idx < MAX_BUSES_PER_PLAYBACK; idx++) { - if (!bus_details->bus_active[idx]) { + if (!bus_details.bus_active[idx]) { continue; } - int bus_idx = thread_find_bus_index(bus_details->bus[idx]); + int bus_idx = thread_find_bus_index(bus_details.bus[idx]); int prev_bus_idx = -1; for (int search_idx = 0; search_idx < MAX_BUSES_PER_PLAYBACK; search_idx++) { - if (!prev_bus_details->bus_active[search_idx]) { + if (!playback->prev_bus_details->bus_active[search_idx]) { continue; } - if (prev_bus_details->bus[search_idx].hash() == bus_details->bus[idx].hash()) { + if (playback->prev_bus_details->bus[search_idx].hash() == bus_details.bus[idx].hash()) { prev_bus_idx = search_idx; } } @@ -411,13 +407,13 @@ void AudioServer::_mix_step() { for (int channel_idx = 0; channel_idx < channel_count; channel_idx++) { AudioFrame *channel_buf = thread_get_channel_mix_buffer(bus_idx, channel_idx); if (fading_out) { - bus_details->volume[idx][channel_idx] = AudioFrame(0, 0); + bus_details.volume[idx][channel_idx] = AudioFrame(0, 0); } - AudioFrame channel_vol = bus_details->volume[idx][channel_idx]; + AudioFrame channel_vol = bus_details.volume[idx][channel_idx]; AudioFrame prev_channel_vol = AudioFrame(0, 0); if (prev_bus_idx != -1) { - prev_channel_vol = prev_bus_details->volume[prev_bus_idx][channel_idx]; + prev_channel_vol = playback->prev_bus_details->volume[prev_bus_idx][channel_idx]; } _mix_step_for_channel(channel_buf, buf, prev_channel_vol, channel_vol, playback->attenuation_filter_cutoff_hz.get(), playback->highshelf_gain.get(), &playback->filter_process[channel_idx * 2], &playback->filter_process[channel_idx * 2 + 1]); } @@ -425,14 +421,14 @@ void AudioServer::_mix_step() { // Now go through and fade-out any buses that were being played to previously that we missed by going through current data. for (int idx = 0; idx < MAX_BUSES_PER_PLAYBACK; idx++) { - if (!prev_bus_details->bus_active[idx]) { + if (!playback->prev_bus_details->bus_active[idx]) { continue; } - int bus_idx = thread_find_bus_index(prev_bus_details->bus[idx]); + int bus_idx = thread_find_bus_index(playback->prev_bus_details->bus[idx]); int current_bus_idx = -1; for (int search_idx = 0; search_idx < MAX_BUSES_PER_PLAYBACK; search_idx++) { - if (bus_details->bus[search_idx] == prev_bus_details->bus[idx]) { + if (bus_details.bus[search_idx] == playback->prev_bus_details->bus[idx]) { current_bus_idx = search_idx; } } @@ -443,24 +439,17 @@ void AudioServer::_mix_step() { for (int channel_idx = 0; channel_idx < channel_count; channel_idx++) { AudioFrame *channel_buf = thread_get_channel_mix_buffer(bus_idx, channel_idx); - AudioFrame prev_channel_vol = prev_bus_details->volume[idx][channel_idx]; + AudioFrame prev_channel_vol = playback->prev_bus_details->volume[idx][channel_idx]; // Fade out to silence _mix_step_for_channel(channel_buf, buf, prev_channel_vol, AudioFrame(0, 0), playback->attenuation_filter_cutoff_hz.get(), playback->highshelf_gain.get(), &playback->filter_process[channel_idx * 2], &playback->filter_process[channel_idx * 2 + 1]); } } // Copy the bus details we mixed with to the previous bus details to maintain volume ramps. - std::copy(std::begin(bus_details->bus_active), std::end(bus_details->bus_active), std::begin(prev_bus_details->bus_active)); - std::copy(std::begin(bus_details->bus), std::end(bus_details->bus), std::begin(prev_bus_details->bus)); + std::copy(std::begin(bus_details.bus_active), std::end(bus_details.bus_active), std::begin(playback->prev_bus_details->bus_active)); + std::copy(std::begin(bus_details.bus), std::end(bus_details.bus), std::begin(playback->prev_bus_details->bus)); for (int bus_idx = 0; bus_idx < MAX_BUSES_PER_PLAYBACK; bus_idx++) { - std::copy(std::begin(bus_details->volume[bus_idx]), std::end(bus_details->volume[bus_idx]), std::begin(prev_bus_details->volume[bus_idx])); - } - - AudioStreamPlaybackBusDetails *bus_details_expected = nullptr; - // Only put the bus details pointer back if it hasn't been updated already. - if (!playback->bus_details.compare_exchange_strong(/* expected= */ bus_details_expected, /* new= */ bus_details)) { - // If it *has* been updated already, queue the old one for deletion. - bus_details_graveyard.insert(bus_details); + std::copy(std::begin(bus_details.volume[bus_idx]), std::end(bus_details.volume[bus_idx]), std::begin(playback->prev_bus_details->volume[bus_idx])); } switch (playback->state.load()) { @@ -773,7 +762,7 @@ void AudioServer::remove_bus(int p_index) { lock(); bus_map.erase(buses[p_index]->name); memdelete(buses[p_index]); - buses.remove(p_index); + buses.remove_at(p_index); unlock(); emit_signal(SNAME("bus_layout_changed")); @@ -844,7 +833,7 @@ void AudioServer::move_bus(int p_bus, int p_to_pos) { } Bus *bus = buses[p_bus]; - buses.remove(p_bus); + buses.remove_at(p_bus); if (p_to_pos == -1) { buses.push_back(bus); @@ -1037,7 +1026,7 @@ void AudioServer::remove_bus_effect(int p_bus, int p_effect) { lock(); - buses[p_bus]->effects.remove(p_effect); + buses[p_bus]->effects.remove_at(p_effect); _update_bus_effects(p_bus); unlock(); @@ -1123,16 +1112,16 @@ float AudioServer::get_playback_speed_scale() const { return playback_speed_scale; } -void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time) { +void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time, float p_pitch_scale) { ERR_FAIL_COND(p_playback.is_null()); Map<StringName, Vector<AudioFrame>> map; map[p_bus] = p_volume_db_vector; - start_playback_stream(p_playback, map, p_start_time); + start_playback_stream(p_playback, map, p_start_time, p_pitch_scale); } -void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time) { +void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time, float p_pitch_scale, float p_highshelf_gain, float p_attenuation_cutoff_hz) { ERR_FAIL_COND(p_playback.is_null()); AudioStreamPlaybackListNode *playback_node = new AudioStreamPlaybackListNode(); @@ -1142,8 +1131,10 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map AudioStreamPlaybackBusDetails *new_bus_details = new AudioStreamPlaybackBusDetails(); int idx = 0; for (KeyValue<StringName, Vector<AudioFrame>> pair : p_bus_volumes) { - ERR_FAIL_COND(pair.value.size() < channel_count); - ERR_FAIL_COND(pair.value.size() != MAX_CHANNELS_PER_BUS); + if (pair.value.size() < channel_count || pair.value.size() != MAX_CHANNELS_PER_BUS) { + delete new_bus_details; + ERR_FAIL(); + } new_bus_details->bus_active[idx] = true; new_bus_details->bus[idx] = pair.key; @@ -1154,10 +1145,9 @@ void AudioServer::start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map playback_node->bus_details = new_bus_details; playback_node->prev_bus_details = new AudioStreamPlaybackBusDetails(); - playback_node->setseek.set(-1); - playback_node->pitch_scale.set(1); - playback_node->highshelf_gain.set(0); - playback_node->attenuation_filter_cutoff_hz.set(0); + playback_node->pitch_scale.set(p_pitch_scale); + playback_node->highshelf_gain.set(p_highshelf_gain); + playback_node->attenuation_filter_cutoff_hz.set(p_attenuation_cutoff_hz); memset(playback_node->prev_bus_details->volume, 0, sizeof(playback_node->prev_bus_details->volume)); @@ -1181,6 +1171,9 @@ void AudioServer::stop_playback_stream(Ref<AudioStreamPlayback> p_playback) { AudioStreamPlaybackListNode::PlaybackState new_state, old_state; do { old_state = playback_node->state.load(); + if (old_state == AudioStreamPlaybackListNode::AWAITING_DELETION) { + break; // Don't fade out again. + } new_state = AudioStreamPlaybackListNode::FADE_OUT_TO_DELETION; } while (!playback_node->state.compare_exchange_strong(old_state, new_state)); @@ -1206,6 +1199,9 @@ void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_pla int idx = 0; for (KeyValue<StringName, Vector<AudioFrame>> pair : p_bus_volumes) { + if (idx >= MAX_BUSES_PER_PLAYBACK) { + break; + } ERR_FAIL_COND(pair.value.size() < channel_count); ERR_FAIL_COND(pair.value.size() != MAX_CHANNELS_PER_BUS); @@ -1214,6 +1210,7 @@ void AudioServer::set_playback_bus_volumes_linear(Ref<AudioStreamPlayback> p_pla for (int channel_idx = 0; channel_idx < MAX_CHANNELS_PER_BUS; channel_idx++) { new_bus_details->volume[idx][channel_idx] = pair.value[channel_idx]; } + idx++; } do { @@ -1260,17 +1257,18 @@ void AudioServer::set_playback_paused(Ref<AudioStreamPlayback> p_playback, bool if (!playback_node) { return; } - if (!p_paused && playback_node->state == AudioStreamPlaybackListNode::PLAYING) { - return; // No-op. - } - if (p_paused && (playback_node->state == AudioStreamPlaybackListNode::PAUSED || playback_node->state == AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE)) { - return; // No-op. - } AudioStreamPlaybackListNode::PlaybackState new_state, old_state; do { old_state = playback_node->state.load(); new_state = p_paused ? AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE : AudioStreamPlaybackListNode::PLAYING; + if (!p_paused && old_state == AudioStreamPlaybackListNode::PLAYING) { + return; // No-op. + } + if (p_paused && (old_state == AudioStreamPlaybackListNode::PAUSED || old_state == AudioStreamPlaybackListNode::FADE_OUT_TO_PAUSE)) { + return; // No-op. + } + } while (!playback_node->state.compare_exchange_strong(old_state, new_state)); } @@ -1444,10 +1442,15 @@ void AudioServer::update() { update_callback_list.maybe_cleanup(); listener_changed_callback_list.maybe_cleanup(); playback_list.maybe_cleanup(); + for (AudioStreamPlaybackBusDetails *bus_details : bus_details_graveyard_frame_old) { + bus_details_graveyard_frame_old.erase(bus_details, [](AudioStreamPlaybackBusDetails *d) { delete d; }); + } for (AudioStreamPlaybackBusDetails *bus_details : bus_details_graveyard) { - bus_details_graveyard.erase(bus_details, [](AudioStreamPlaybackBusDetails *d) { delete d; }); + bus_details_graveyard_frame_old.insert(bus_details); + bus_details_graveyard.erase(bus_details); } bus_details_graveyard.maybe_cleanup(); + bus_details_graveyard_frame_old.maybe_cleanup(); } void AudioServer::load_default_bus_layout() { @@ -1861,16 +1864,16 @@ bool AudioBusLayout::_get(const StringName &p_name, Variant &r_ret) const { void AudioBusLayout::_get_property_list(List<PropertyInfo> *p_list) const { for (int i = 0; i < buses.size(); i++) { - p_list->push_back(PropertyInfo(Variant::STRING, "bus/" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::BOOL, "bus/" + itos(i) + "/solo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::BOOL, "bus/" + itos(i) + "/mute", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::BOOL, "bus/" + itos(i) + "/bypass_fx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::FLOAT, "bus/" + itos(i) + "/volume_db", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::FLOAT, "bus/" + itos(i) + "/send", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::STRING, "bus/" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::BOOL, "bus/" + itos(i) + "/solo", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::BOOL, "bus/" + itos(i) + "/mute", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::BOOL, "bus/" + itos(i) + "/bypass_fx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::FLOAT, "bus/" + itos(i) + "/volume_db", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::FLOAT, "bus/" + itos(i) + "/send", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); for (int j = 0; j < buses[i].effects.size(); j++) { - p_list->push_back(PropertyInfo(Variant::OBJECT, "bus/" + itos(i) + "/effect/" + itos(j) + "/effect", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); - p_list->push_back(PropertyInfo(Variant::BOOL, "bus/" + itos(i) + "/effect/" + itos(j) + "/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::OBJECT, "bus/" + itos(i) + "/effect/" + itos(j) + "/effect", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); + p_list->push_back(PropertyInfo(Variant::BOOL, "bus/" + itos(i) + "/effect/" + itos(j) + "/enabled", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); } } } diff --git a/servers/audio_server.h b/servers/audio_server.h index affcb3df7b..46873845dc 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -163,7 +163,7 @@ public: AUDIO_DATA_INVALID_ID = -1, MAX_CHANNELS_PER_BUS = 4, MAX_BUSES_PER_PLAYBACK = 6, - LOOKAHEAD_BUFFER_SIZE = 32, + LOOKAHEAD_BUFFER_SIZE = 64, }; typedef void (*AudioCallback)(void *p_userdata); @@ -262,6 +262,9 @@ private: SafeList<AudioStreamPlaybackListNode *> playback_list; SafeList<AudioStreamPlaybackBusDetails *> bus_details_graveyard; + // TODO document if this is necessary. + SafeList<AudioStreamPlaybackBusDetails *> bus_details_graveyard_frame_old; + Vector<Vector<AudioFrame>> temp_buffer; //temp_buffer for each level Vector<AudioFrame> mix_buffer; Vector<Bus *> buses; @@ -364,8 +367,10 @@ public: void set_playback_speed_scale(float p_scale); float get_playback_speed_scale() const; - void start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0); - void start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time = 0); + // Convenience method. + void start_playback_stream(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volume_db_vector, float p_start_time = 0, float p_pitch_scale = 1); + // Expose all parameters. + void start_playback_stream(Ref<AudioStreamPlayback> p_playback, Map<StringName, Vector<AudioFrame>> p_bus_volumes, float p_start_time = 0, float p_pitch_scale = 1, float p_highshelf_gain = 0, float p_attenuation_cutoff_hz = 0); void stop_playback_stream(Ref<AudioStreamPlayback> p_playback); void set_playback_bus_exclusive(Ref<AudioStreamPlayback> p_playback, StringName p_bus, Vector<AudioFrame> p_volumes); diff --git a/servers/camera_server.cpp b/servers/camera_server.cpp index 6f506d0f7a..8391a2ee2e 100644 --- a/servers/camera_server.cpp +++ b/servers/camera_server.cpp @@ -124,7 +124,7 @@ void CameraServer::remove_feed(const Ref<CameraFeed> &p_feed) { #endif // remove it from our array, if this results in our feed being unreferenced it will be destroyed - feeds.remove(i); + feeds.remove_at(i); // let whomever is interested know emit_signal(SNAME("camera_feed_removed"), feed_id); diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 3d44484033..8b5a965738 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -148,7 +148,7 @@ Point2i DisplayServer::mouse_get_position() const { } MouseButton DisplayServer::mouse_get_button_state() const { - ERR_FAIL_V_MSG(MOUSE_BUTTON_NONE, "Mouse is not supported by this display server."); + ERR_FAIL_V_MSG(MouseButton::NONE, "Mouse is not supported by this display server."); } void DisplayServer::clipboard_set(const String &p_text) { @@ -159,6 +159,14 @@ String DisplayServer::clipboard_get() const { ERR_FAIL_V_MSG(String(), "Clipboard is not supported by this display server."); } +void DisplayServer::clipboard_set_primary(const String &p_text) { + WARN_PRINT("Primary clipboard is not supported by this display server."); +} + +String DisplayServer::clipboard_get_primary() const { + ERR_FAIL_V_MSG(String(), "Primary clipboard is not supported by this display server."); +} + void DisplayServer::screen_set_orientation(ScreenOrientation p_orientation, int p_screen) { WARN_PRINT("Orientation not supported by this display server."); } @@ -200,6 +208,10 @@ void DisplayServer::window_set_mouse_passthrough(const Vector<Vector2> &p_region ERR_FAIL_MSG("Mouse passthrough not supported by this display server."); } +void DisplayServer::gl_window_make_current(DisplayServer::WindowID p_window_id) { + // noop except in gles +} + void DisplayServer::window_set_ime_active(const bool p_active, WindowID p_window) { WARN_PRINT("IME not supported by this display server."); } @@ -285,6 +297,10 @@ String DisplayServer::keyboard_get_layout_name(int p_index) const { return "Not supported"; } +Key DisplayServer::keyboard_get_keycode_from_physical(Key p_keycode) const { + ERR_FAIL_V_MSG(p_keycode, "Not supported by this display server."); +} + void DisplayServer::force_process_and_drop_events() { } @@ -356,6 +372,8 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("clipboard_set", "clipboard"), &DisplayServer::clipboard_set); ClassDB::bind_method(D_METHOD("clipboard_get"), &DisplayServer::clipboard_get); + ClassDB::bind_method(D_METHOD("clipboard_set_primary", "clipboard_primary"), &DisplayServer::clipboard_set_primary); + ClassDB::bind_method(D_METHOD("clipboard_get_primary"), &DisplayServer::clipboard_get_primary); ClassDB::bind_method(D_METHOD("get_screen_count"), &DisplayServer::get_screen_count); ClassDB::bind_method(D_METHOD("screen_get_position", "screen"), &DisplayServer::screen_get_position, DEFVAL(SCREEN_OF_MAIN_WINDOW)); @@ -452,6 +470,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("keyboard_set_current_layout", "index"), &DisplayServer::keyboard_set_current_layout); ClassDB::bind_method(D_METHOD("keyboard_get_layout_language", "index"), &DisplayServer::keyboard_get_layout_language); ClassDB::bind_method(D_METHOD("keyboard_get_layout_name", "index"), &DisplayServer::keyboard_get_layout_name); + ClassDB::bind_method(D_METHOD("keyboard_get_keycode_from_physical", "keycode"), &DisplayServer::keyboard_get_keycode_from_physical); ClassDB::bind_method(D_METHOD("process_events"), &DisplayServer::process_events); ClassDB::bind_method(D_METHOD("force_process_and_drop_events"), &DisplayServer::force_process_and_drop_events); @@ -482,6 +501,7 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_NATIVE_ICON); BIND_ENUM_CONSTANT(FEATURE_ORIENTATION); BIND_ENUM_CONSTANT(FEATURE_SWAP_BUFFERS); + BIND_ENUM_CONSTANT(FEATURE_CLIPBOARD_PRIMARY); BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); @@ -605,4 +625,5 @@ DisplayServer::DisplayServer() { } DisplayServer::~DisplayServer() { + singleton = nullptr; } diff --git a/servers/display_server.h b/servers/display_server.h index 788206768c..2d837dbef9 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -114,6 +114,7 @@ public: FEATURE_ORIENTATION, FEATURE_SWAP_BUFFERS, FEATURE_KEEP_SCREEN_ON, + FEATURE_CLIPBOARD_PRIMARY, }; virtual bool has_feature(Feature p_feature) const = 0; @@ -161,6 +162,8 @@ public: virtual void clipboard_set(const String &p_text); virtual String clipboard_get() const; + virtual void clipboard_set_primary(const String &p_text); + virtual String clipboard_get_primary() const; enum { SCREEN_OF_MAIN_WINDOW = -1 @@ -295,6 +298,9 @@ public: virtual void window_set_ime_active(const bool p_active, WindowID p_window = MAIN_WINDOW_ID); virtual void window_set_ime_position(const Point2i &p_pos, WindowID p_window = MAIN_WINDOW_ID); + // necessary for GL focus, may be able to use one of the existing functions for this, not sure yet + virtual void gl_window_make_current(DisplayServer::WindowID p_window_id); + virtual Point2i ime_get_selection() const; virtual String ime_get_text() const; @@ -343,6 +349,7 @@ public: virtual void keyboard_set_current_layout(int p_index); virtual String keyboard_get_layout_language(int p_index) const; virtual String keyboard_get_layout_name(int p_index) const; + virtual Key keyboard_get_keycode_from_physical(Key p_keycode) const; virtual int tablet_get_driver_count() const { return 1; }; virtual String tablet_get_driver_name(int p_driver) const { return "default"; }; diff --git a/servers/physics_2d/area_2d_sw.cpp b/servers/physics_2d/godot_area_2d.cpp index 663a47f273..c4060615c9 100644 --- a/servers/physics_2d/area_2d_sw.cpp +++ b/servers/physics_2d/godot_area_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* area_2d_sw.cpp */ +/* godot_area_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,31 +28,31 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "area_2d_sw.h" -#include "body_2d_sw.h" -#include "space_2d_sw.h" +#include "godot_area_2d.h" +#include "godot_body_2d.h" +#include "godot_space_2d.h" -Area2DSW::BodyKey::BodyKey(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +GodotArea2D::BodyKey::BodyKey(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { rid = p_body->get_self(); instance_id = p_body->get_instance_id(); body_shape = p_body_shape; area_shape = p_area_shape; } -Area2DSW::BodyKey::BodyKey(Area2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +GodotArea2D::BodyKey::BodyKey(GodotArea2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { rid = p_body->get_self(); instance_id = p_body->get_instance_id(); body_shape = p_body_shape; area_shape = p_area_shape; } -void Area2DSW::_shapes_changed() { +void GodotArea2D::_shapes_changed() { if (!moved_list.in_list() && get_space()) { get_space()->area_add_to_moved_list(&moved_list); } } -void Area2DSW::set_transform(const Transform2D &p_transform) { +void GodotArea2D::set_transform(const Transform2D &p_transform) { if (!moved_list.in_list() && get_space()) { get_space()->area_add_to_moved_list(&moved_list); } @@ -61,7 +61,7 @@ void Area2DSW::set_transform(const Transform2D &p_transform) { _set_inv_transform(p_transform.affine_inverse()); } -void Area2DSW::set_space(Space2DSW *p_space) { +void GodotArea2D::set_space(GodotSpace2D *p_space) { if (get_space()) { if (monitor_query_list.in_list()) { get_space()->area_remove_from_monitor_query_list(&monitor_query_list); @@ -77,16 +77,17 @@ void Area2DSW::set_space(Space2DSW *p_space) { _set_space(p_space); } -void Area2DSW::set_monitor_callback(ObjectID p_id, const StringName &p_method) { - if (p_id == monitor_callback_id) { - monitor_callback_method = p_method; +void GodotArea2D::set_monitor_callback(const Callable &p_callback) { + ObjectID id = p_callback.get_object_id(); + + if (id == monitor_callback.get_object_id()) { + monitor_callback = p_callback; return; } _unregister_shapes(); - monitor_callback_id = p_id; - monitor_callback_method = p_method; + monitor_callback = p_callback; monitored_bodies.clear(); monitored_areas.clear(); @@ -98,16 +99,17 @@ void Area2DSW::set_monitor_callback(ObjectID p_id, const StringName &p_method) { } } -void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_method) { - if (p_id == area_monitor_callback_id) { - area_monitor_callback_method = p_method; +void GodotArea2D::set_area_monitor_callback(const Callable &p_callback) { + ObjectID id = p_callback.get_object_id(); + + if (id == area_monitor_callback.get_object_id()) { + area_monitor_callback = p_callback; return; } _unregister_shapes(); - area_monitor_callback_id = p_id; - area_monitor_callback_method = p_method; + area_monitor_callback = p_callback; monitored_bodies.clear(); monitored_areas.clear(); @@ -119,18 +121,21 @@ void Area2DSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_meth } } -void Area2DSW::set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode p_mode) { - bool do_override = p_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED; - if (do_override == (space_override_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED)) { +void GodotArea2D::_set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode &r_mode, PhysicsServer2D::AreaSpaceOverrideMode p_new_mode) { + bool do_override = p_new_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED; + if (do_override == (r_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED)) { return; } _unregister_shapes(); - space_override_mode = p_mode; + r_mode = p_new_mode; _shape_changed(); } -void Area2DSW::set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value) { +void GodotArea2D::set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value) { switch (p_param) { + case PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE: + _set_space_override_mode(gravity_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value); + break; case PhysicsServer2D::AREA_PARAM_GRAVITY: gravity = p_value; break; @@ -146,9 +151,15 @@ void Area2DSW::set_param(PhysicsServer2D::AreaParameter p_param, const Variant & case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation = p_value; break; + case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE: + _set_space_override_mode(linear_damping_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value); + break; case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP: linear_damp = p_value; break; + case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE: + _set_space_override_mode(angular_damping_override_mode, (PhysicsServer2D::AreaSpaceOverrideMode)(int)p_value); + break; case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP: angular_damp = p_value; break; @@ -158,8 +169,10 @@ void Area2DSW::set_param(PhysicsServer2D::AreaParameter p_param, const Variant & } } -Variant Area2DSW::get_param(PhysicsServer2D::AreaParameter p_param) const { +Variant GodotArea2D::get_param(PhysicsServer2D::AreaParameter p_param) const { switch (p_param) { + case PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE: + return gravity_override_mode; case PhysicsServer2D::AREA_PARAM_GRAVITY: return gravity; case PhysicsServer2D::AREA_PARAM_GRAVITY_VECTOR: @@ -170,8 +183,12 @@ Variant Area2DSW::get_param(PhysicsServer2D::AreaParameter p_param) const { return gravity_distance_scale; case PhysicsServer2D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation; + case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE: + return linear_damping_override_mode; case PhysicsServer2D::AREA_PARAM_LINEAR_DAMP: return linear_damp; + case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE: + return angular_damping_override_mode; case PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP: return angular_damp; case PhysicsServer2D::AREA_PARAM_PRIORITY: @@ -181,7 +198,7 @@ Variant Area2DSW::get_param(PhysicsServer2D::AreaParameter p_param) const { return Variant(); } -void Area2DSW::_queue_monitor_update() { +void GodotArea2D::_queue_monitor_update() { ERR_FAIL_COND(!get_space()); if (!monitor_query_list.in_list()) { @@ -189,92 +206,91 @@ void Area2DSW::_queue_monitor_update() { } } -void Area2DSW::set_monitorable(bool p_monitorable) { +void GodotArea2D::set_monitorable(bool p_monitorable) { if (monitorable == p_monitorable) { return; } monitorable = p_monitorable; _set_static(!monitorable); + _shapes_changed(); } -void Area2DSW::call_queries() { - if (monitor_callback_id.is_valid() && !monitored_bodies.is_empty()) { - Variant res[5]; - Variant *resptr[5]; - for (int i = 0; i < 5; i++) { - resptr[i] = &res[i]; - } +void GodotArea2D::call_queries() { + if (!monitor_callback.is_null() && !monitored_bodies.is_empty()) { + if (monitor_callback.is_valid()) { + Variant res[5]; + Variant *resptr[5]; + for (int i = 0; i < 5; i++) { + resptr[i] = &res[i]; + } - Object *obj = ObjectDB::get_instance(monitor_callback_id); - if (!obj) { - monitored_bodies.clear(); - monitor_callback_id = ObjectID(); - return; - } + for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) { + if (E->get().state == 0) { // Nothing happened + Map<BodyKey, BodyState>::Element *next = E->next(); + monitored_bodies.erase(E); + E = next; + continue; + } + + res[0] = E->get().state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED; + res[1] = E->key().rid; + res[2] = E->key().instance_id; + res[3] = E->key().body_shape; + res[4] = E->key().area_shape; - for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) { - if (E->get().state == 0) { // Nothing happened Map<BodyKey, BodyState>::Element *next = E->next(); monitored_bodies.erase(E); E = next; - continue; - } - res[0] = E->get().state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED; - res[1] = E->key().rid; - res[2] = E->key().instance_id; - res[3] = E->key().body_shape; - res[4] = E->key().area_shape; - - Map<BodyKey, BodyState>::Element *next = E->next(); - monitored_bodies.erase(E); - E = next; - - Callable::CallError ce; - obj->call(monitor_callback_method, (const Variant **)resptr, 5, ce); + Callable::CallError ce; + Variant ret; + monitor_callback.call((const Variant **)resptr, 5, ret, ce); + } + } else { + monitored_bodies.clear(); + monitor_callback = Callable(); } } - if (area_monitor_callback_id.is_valid() && !monitored_areas.is_empty()) { - Variant res[5]; - Variant *resptr[5]; - for (int i = 0; i < 5; i++) { - resptr[i] = &res[i]; - } + if (!area_monitor_callback.is_null() && !monitored_areas.is_empty()) { + if (area_monitor_callback.is_valid()) { + Variant res[5]; + Variant *resptr[5]; + for (int i = 0; i < 5; i++) { + resptr[i] = &res[i]; + } - Object *obj = ObjectDB::get_instance(area_monitor_callback_id); - if (!obj) { - monitored_areas.clear(); - area_monitor_callback_id = ObjectID(); - return; - } + for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) { + if (E->get().state == 0) { // Nothing happened + Map<BodyKey, BodyState>::Element *next = E->next(); + monitored_areas.erase(E); + E = next; + continue; + } + + res[0] = E->get().state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED; + res[1] = E->key().rid; + res[2] = E->key().instance_id; + res[3] = E->key().body_shape; + res[4] = E->key().area_shape; - for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) { - if (E->get().state == 0) { // Nothing happened Map<BodyKey, BodyState>::Element *next = E->next(); monitored_areas.erase(E); E = next; - continue; - } - - res[0] = E->get().state > 0 ? PhysicsServer2D::AREA_BODY_ADDED : PhysicsServer2D::AREA_BODY_REMOVED; - res[1] = E->key().rid; - res[2] = E->key().instance_id; - res[3] = E->key().body_shape; - res[4] = E->key().area_shape; - - Map<BodyKey, BodyState>::Element *next = E->next(); - monitored_areas.erase(E); - E = next; - Callable::CallError ce; - obj->call(area_monitor_callback_method, (const Variant **)resptr, 5, ce); + Callable::CallError ce; + Variant ret; + area_monitor_callback.call((const Variant **)resptr, 5, ret, ce); + } + } else { + monitored_areas.clear(); + area_monitor_callback = Callable(); } } } -void Area2DSW::compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) const { +void GodotArea2D::compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) const { if (is_gravity_point()) { const real_t gravity_distance_scale = get_gravity_distance_scale(); Vector2 v = get_transform().xform(get_gravity_vector()) - p_position; @@ -294,23 +310,12 @@ void Area2DSW::compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) co } } -Area2DSW::Area2DSW() : - CollisionObject2DSW(TYPE_AREA), +GodotArea2D::GodotArea2D() : + GodotCollisionObject2D(TYPE_AREA), monitor_query_list(this), moved_list(this) { _set_static(true); //areas are not active by default - space_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED; - gravity = 9.80665; - gravity_vector = Vector2(0, -1); - gravity_is_point = false; - gravity_distance_scale = 0; - point_attenuation = 1; - - angular_damp = 1.0; - linear_damp = 0.1; - priority = 0; - monitorable = false; } -Area2DSW::~Area2DSW() { +GodotArea2D::~GodotArea2D() { } diff --git a/servers/physics_2d/area_2d_sw.h b/servers/physics_2d/godot_area_2d.h index d9147d6f1d..699c1c1bc8 100644 --- a/servers/physics_2d/area_2d_sw.h +++ b/servers/physics_2d/godot_area_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* area_2d_sw.h */ +/* godot_area_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,43 +28,45 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AREA_2D_SW_H -#define AREA_2D_SW_H +#ifndef GODOT_AREA_2D_H +#define GODOT_AREA_2D_H + +#include "godot_collision_object_2d.h" -#include "collision_object_2d_sw.h" #include "core/templates/self_list.h" #include "servers/physics_server_2d.h" -class Space2DSW; -class Body2DSW; -class Constraint2DSW; +class GodotSpace2D; +class GodotBody2D; +class GodotConstraint2D; + +class GodotArea2D : public GodotCollisionObject2D { + PhysicsServer2D::AreaSpaceOverrideMode gravity_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED; + PhysicsServer2D::AreaSpaceOverrideMode linear_damping_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED; + PhysicsServer2D::AreaSpaceOverrideMode angular_damping_override_mode = PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED; -class Area2DSW : public CollisionObject2DSW { - PhysicsServer2D::AreaSpaceOverrideMode space_override_mode; - real_t gravity; - Vector2 gravity_vector; - bool gravity_is_point; - real_t gravity_distance_scale; - real_t point_attenuation; - real_t linear_damp; - real_t angular_damp; - int priority; - bool monitorable; + real_t gravity = 9.80665; + Vector2 gravity_vector = Vector2(0, -1); + bool gravity_is_point = false; + real_t gravity_distance_scale = 0.0; + real_t point_attenuation = 1.0; + real_t linear_damp = 0.1; + real_t angular_damp = 1.0; + int priority = 0; + bool monitorable = false; - ObjectID monitor_callback_id; - StringName monitor_callback_method; + Callable monitor_callback; - ObjectID area_monitor_callback_id; - StringName area_monitor_callback_method; + Callable area_monitor_callback; - SelfList<Area2DSW> monitor_query_list; - SelfList<Area2DSW> moved_list; + SelfList<GodotArea2D> monitor_query_list; + SelfList<GodotArea2D> moved_list; struct BodyKey { RID rid; ObjectID instance_id; - uint32_t body_shape; - uint32_t area_shape; + uint32_t body_shape = 0; + uint32_t area_shape = 0; _FORCE_INLINE_ bool operator<(const BodyKey &p_key) const { if (rid == p_key.rid) { @@ -79,44 +81,42 @@ class Area2DSW : public CollisionObject2DSW { } _FORCE_INLINE_ BodyKey() {} - BodyKey(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); - BodyKey(Area2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + BodyKey(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + BodyKey(GodotArea2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); }; struct BodyState { - int state; + int state = 0; _FORCE_INLINE_ void inc() { state++; } _FORCE_INLINE_ void dec() { state--; } - _FORCE_INLINE_ BodyState() { state = 0; } }; Map<BodyKey, BodyState> monitored_bodies; Map<BodyKey, BodyState> monitored_areas; - Set<Constraint2DSW *> constraints; + Set<GodotConstraint2D *> constraints; virtual void _shapes_changed(); void _queue_monitor_update(); + void _set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode &r_mode, PhysicsServer2D::AreaSpaceOverrideMode p_new_mode); + public: - void set_monitor_callback(ObjectID p_id, const StringName &p_method); - _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id.is_valid(); } + void set_monitor_callback(const Callable &p_callback); + _FORCE_INLINE_ bool has_monitor_callback() const { return !monitor_callback.is_null(); } - void set_area_monitor_callback(ObjectID p_id, const StringName &p_method); - _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id.is_valid(); } + void set_area_monitor_callback(const Callable &p_callback); + _FORCE_INLINE_ bool has_area_monitor_callback() const { return !area_monitor_callback.is_null(); } - _FORCE_INLINE_ void add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); - _FORCE_INLINE_ void remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void add_body_to_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void remove_body_from_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); - _FORCE_INLINE_ void add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape); - _FORCE_INLINE_ void remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape); + _FORCE_INLINE_ void add_area_to_query(GodotArea2D *p_area, uint32_t p_area_shape, uint32_t p_self_shape); + _FORCE_INLINE_ void remove_area_from_query(GodotArea2D *p_area, uint32_t p_area_shape, uint32_t p_self_shape); void set_param(PhysicsServer2D::AreaParameter p_param, const Variant &p_value); Variant get_param(PhysicsServer2D::AreaParameter p_param) const; - void set_space_override_mode(PhysicsServer2D::AreaSpaceOverrideMode p_mode); - PhysicsServer2D::AreaSpaceOverrideMode get_space_override_mode() const { return space_override_mode; } - _FORCE_INLINE_ void set_gravity(real_t p_gravity) { gravity = p_gravity; } _FORCE_INLINE_ real_t get_gravity() const { return gravity; } @@ -141,9 +141,9 @@ public: _FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; } _FORCE_INLINE_ int get_priority() const { return priority; } - _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint) { constraints.insert(p_constraint); } - _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint) { constraints.erase(p_constraint); } - _FORCE_INLINE_ const Set<Constraint2DSW *> &get_constraints() const { return constraints; } + _FORCE_INLINE_ void add_constraint(GodotConstraint2D *p_constraint) { constraints.insert(p_constraint); } + _FORCE_INLINE_ void remove_constraint(GodotConstraint2D *p_constraint) { constraints.erase(p_constraint); } + _FORCE_INLINE_ const Set<GodotConstraint2D *> &get_constraints() const { return constraints; } _FORCE_INLINE_ void clear_constraints() { constraints.clear(); } void set_monitorable(bool p_monitorable); @@ -151,17 +151,17 @@ public: void set_transform(const Transform2D &p_transform); - void set_space(Space2DSW *p_space); + void set_space(GodotSpace2D *p_space); void call_queries(); void compute_gravity(const Vector2 &p_position, Vector2 &r_gravity) const; - Area2DSW(); - ~Area2DSW(); + GodotArea2D(); + ~GodotArea2D(); }; -void Area2DSW::add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +void GodotArea2D::add_body_to_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { BodyKey bk(p_body, p_body_shape, p_area_shape); monitored_bodies[bk].inc(); if (!monitor_query_list.in_list()) { @@ -169,7 +169,7 @@ void Area2DSW::add_body_to_query(Body2DSW *p_body, uint32_t p_body_shape, uint32 } } -void Area2DSW::remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +void GodotArea2D::remove_body_from_query(GodotBody2D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { BodyKey bk(p_body, p_body_shape, p_area_shape); monitored_bodies[bk].dec(); if (!monitor_query_list.in_list()) { @@ -177,7 +177,7 @@ void Area2DSW::remove_body_from_query(Body2DSW *p_body, uint32_t p_body_shape, u } } -void Area2DSW::add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) { +void GodotArea2D::add_area_to_query(GodotArea2D *p_area, uint32_t p_area_shape, uint32_t p_self_shape) { BodyKey bk(p_area, p_area_shape, p_self_shape); monitored_areas[bk].inc(); if (!monitor_query_list.in_list()) { @@ -185,7 +185,7 @@ void Area2DSW::add_area_to_query(Area2DSW *p_area, uint32_t p_area_shape, uint32 } } -void Area2DSW::remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) { +void GodotArea2D::remove_area_from_query(GodotArea2D *p_area, uint32_t p_area_shape, uint32_t p_self_shape) { BodyKey bk(p_area, p_area_shape, p_self_shape); monitored_areas[bk].dec(); if (!monitor_query_list.in_list()) { @@ -193,4 +193,4 @@ void Area2DSW::remove_area_from_query(Area2DSW *p_area, uint32_t p_area_shape, u } } -#endif // AREA_2D_SW_H +#endif // GODOT_AREA_2D_H diff --git a/servers/physics_2d/area_pair_2d_sw.cpp b/servers/physics_2d/godot_area_pair_2d.cpp index 4f1148c26f..bde22aab11 100644 --- a/servers/physics_2d/area_pair_2d_sw.cpp +++ b/servers/physics_2d/godot_area_pair_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* area_pair_2d_sw.cpp */ +/* godot_area_pair_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,28 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "area_pair_2d_sw.h" -#include "collision_solver_2d_sw.h" +#include "godot_area_pair_2d.h" +#include "godot_collision_solver_2d.h" -bool AreaPair2DSW::setup(real_t p_step) { +bool GodotAreaPair2D::setup(real_t p_step) { bool result = false; - if (area->collides_with(body) && CollisionSolver2DSW::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) { + if (area->collides_with(body) && GodotCollisionSolver2D::solve(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), Vector2(), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), Vector2(), nullptr, this)) { result = true; } process_collision = false; + has_space_override = false; if (result != colliding) { - if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { - process_collision = true; - } else if (area->has_monitor_callback()) { + if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + has_space_override = true; + } else if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + has_space_override = true; + } else if ((int)area->get_param(PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE) != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + has_space_override = true; + } + process_collision = has_space_override; + + if (area->has_monitor_callback()) { process_collision = true; } @@ -51,13 +59,13 @@ bool AreaPair2DSW::setup(real_t p_step) { return process_collision; } -bool AreaPair2DSW::pre_solve(real_t p_step) { +bool GodotAreaPair2D::pre_solve(real_t p_step) { if (!process_collision) { return false; } if (colliding) { - if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { body->add_area(area); } @@ -65,7 +73,7 @@ bool AreaPair2DSW::pre_solve(real_t p_step) { area->add_body_to_query(body, body_shape, area_shape); } } else { - if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { body->remove_area(area); } @@ -77,11 +85,11 @@ bool AreaPair2DSW::pre_solve(real_t p_step) { return false; // Never do any post solving. } -void AreaPair2DSW::solve(real_t p_step) { +void GodotAreaPair2D::solve(real_t p_step) { // Nothing to do. } -AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape) { +GodotAreaPair2D::GodotAreaPair2D(GodotBody2D *p_body, int p_body_shape, GodotArea2D *p_area, int p_area_shape) { body = p_body; area = p_area; body_shape = p_body_shape; @@ -93,9 +101,9 @@ AreaPair2DSW::AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, } } -AreaPair2DSW::~AreaPair2DSW() { +GodotAreaPair2D::~GodotAreaPair2D() { if (colliding) { - if (area->get_space_override_mode() != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { body->remove_area(area); } if (area->has_monitor_callback()) { @@ -108,10 +116,10 @@ AreaPair2DSW::~AreaPair2DSW() { ////////////////////////////////// -bool Area2Pair2DSW::setup(real_t p_step) { +bool GodotArea2Pair2D::setup(real_t p_step) { bool result_a = area_a->collides_with(area_b); bool result_b = area_b->collides_with(area_a); - if ((result_a || result_b) && !CollisionSolver2DSW::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) { + if ((result_a || result_b) && !GodotCollisionSolver2D::solve(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), Vector2(), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), Vector2(), nullptr, this)) { result_a = false; result_b = false; } @@ -120,7 +128,7 @@ bool Area2Pair2DSW::setup(real_t p_step) { process_collision_a = false; if (result_a != colliding_a) { - if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + if (area_a->has_area_monitor_callback() && area_b_monitorable) { process_collision_a = true; process_collision = true; } @@ -129,7 +137,7 @@ bool Area2Pair2DSW::setup(real_t p_step) { process_collision_b = false; if (result_b != colliding_b) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + if (area_b->has_area_monitor_callback() && area_a_monitorable) { process_collision_b = true; process_collision = true; } @@ -139,7 +147,7 @@ bool Area2Pair2DSW::setup(real_t p_step) { return process_collision; } -bool Area2Pair2DSW::pre_solve(real_t p_step) { +bool GodotArea2Pair2D::pre_solve(real_t p_step) { if (process_collision_a) { if (colliding_a) { area_a->add_area_to_query(area_b, shape_b, shape_a); @@ -159,28 +167,30 @@ bool Area2Pair2DSW::pre_solve(real_t p_step) { return false; // Never do any post solving. } -void Area2Pair2DSW::solve(real_t p_step) { +void GodotArea2Pair2D::solve(real_t p_step) { // Nothing to do. } -Area2Pair2DSW::Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b) { +GodotArea2Pair2D::GodotArea2Pair2D(GodotArea2D *p_area_a, int p_shape_a, GodotArea2D *p_area_b, int p_shape_b) { area_a = p_area_a; area_b = p_area_b; shape_a = p_shape_a; shape_b = p_shape_b; + area_a_monitorable = area_a->is_monitorable(); + area_b_monitorable = area_b->is_monitorable(); area_a->add_constraint(this); area_b->add_constraint(this); } -Area2Pair2DSW::~Area2Pair2DSW() { +GodotArea2Pair2D::~GodotArea2Pair2D() { if (colliding_a) { - if (area_a->has_area_monitor_callback()) { + if (area_a->has_area_monitor_callback() && area_b_monitorable) { area_a->remove_area_from_query(area_b, shape_b, shape_a); } } if (colliding_b) { - if (area_b->has_area_monitor_callback()) { + if (area_b->has_area_monitor_callback() && area_a_monitorable) { area_b->remove_area_from_query(area_a, shape_a, shape_b); } } diff --git a/servers/physics_2d/area_pair_2d_sw.h b/servers/physics_2d/godot_area_pair_2d.h index 66e9f1afee..f1290a27d0 100644 --- a/servers/physics_2d/area_pair_2d_sw.h +++ b/servers/physics_2d/godot_area_pair_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* area_pair_2d_sw.h */ +/* godot_area_pair_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,19 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AREA_PAIR_2D_SW_H -#define AREA_PAIR_2D_SW_H +#ifndef GODOT_AREA_PAIR_2D_H +#define GODOT_AREA_PAIR_2D_H -#include "area_2d_sw.h" -#include "body_2d_sw.h" -#include "constraint_2d_sw.h" +#include "godot_area_2d.h" +#include "godot_body_2d.h" +#include "godot_constraint_2d.h" -class AreaPair2DSW : public Constraint2DSW { - Body2DSW *body = nullptr; - Area2DSW *area = nullptr; +class GodotAreaPair2D : public GodotConstraint2D { + GodotBody2D *body = nullptr; + GodotArea2D *area = nullptr; int body_shape = 0; int area_shape = 0; bool colliding = false; + bool has_space_override = false; bool process_collision = false; public: @@ -48,27 +49,29 @@ public: virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - AreaPair2DSW(Body2DSW *p_body, int p_body_shape, Area2DSW *p_area, int p_area_shape); - ~AreaPair2DSW(); + GodotAreaPair2D(GodotBody2D *p_body, int p_body_shape, GodotArea2D *p_area, int p_area_shape); + ~GodotAreaPair2D(); }; -class Area2Pair2DSW : public Constraint2DSW { - Area2DSW *area_a = nullptr; - Area2DSW *area_b = nullptr; +class GodotArea2Pair2D : public GodotConstraint2D { + GodotArea2D *area_a = nullptr; + GodotArea2D *area_b = nullptr; int shape_a = 0; int shape_b = 0; bool colliding_a = false; bool colliding_b = false; bool process_collision_a = false; bool process_collision_b = false; + bool area_a_monitorable; + bool area_b_monitorable; public: virtual bool setup(real_t p_step) override; virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - Area2Pair2DSW(Area2DSW *p_area_a, int p_shape_a, Area2DSW *p_area_b, int p_shape_b); - ~Area2Pair2DSW(); + GodotArea2Pair2D(GodotArea2D *p_area_a, int p_shape_a, GodotArea2D *p_area_b, int p_shape_b); + ~GodotArea2Pair2D(); }; -#endif // AREA_PAIR_2D_SW_H +#endif // GODOT_AREA_PAIR_2D_H diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/godot_body_2d.cpp index 64f71fd25c..6d1c5539aa 100644 --- a/servers/physics_2d/body_2d_sw.cpp +++ b/servers/physics_2d/godot_body_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_2d_sw.cpp */ +/* godot_body_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,53 +28,78 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "body_2d_sw.h" +#include "godot_body_2d.h" -#include "area_2d_sw.h" -#include "body_direct_state_2d_sw.h" -#include "space_2d_sw.h" +#include "godot_area_2d.h" +#include "godot_body_direct_state_2d.h" +#include "godot_space_2d.h" -void Body2DSW::_update_inertia() { - if (!user_inertia && get_space() && !inertia_update_list.in_list()) { - get_space()->body_add_to_inertia_update_list(&inertia_update_list); +void GodotBody2D::_mass_properties_changed() { + if (get_space() && !mass_properties_update_list.in_list() && (calculate_inertia || calculate_center_of_mass)) { + get_space()->body_add_to_mass_properties_update_list(&mass_properties_update_list); } } -void Body2DSW::update_inertias() { +void GodotBody2D::update_mass_properties() { //update shapes and motions switch (mode) { case PhysicsServer2D::BODY_MODE_DYNAMIC: { - if (user_inertia) { - _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0; - break; - } - //update tensor for allshapes, not the best way but should be somehow OK. (inspired from bullet) real_t total_area = 0; - for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } total_area += get_shape_aabb(i).get_area(); } - inertia = 0; + if (calculate_center_of_mass) { + // We have to recompute the center of mass. + center_of_mass_local = Vector2(); - for (int i = 0; i < get_shape_count(); i++) { - if (is_shape_disabled(i)) { - continue; + if (total_area != 0.0) { + for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } + + real_t area = get_shape_aabb(i).get_area(); + + real_t mass = area * this->mass / total_area; + + // NOTE: we assume that the shape origin is also its center of mass. + center_of_mass_local += mass * get_shape_transform(i).get_origin(); + } + + center_of_mass_local /= mass; } + } - const Shape2DSW *shape = get_shape(i); + if (calculate_inertia) { + inertia = 0; - real_t area = get_shape_aabb(i).get_area(); + for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } - real_t mass = area * this->mass / total_area; + const GodotShape2D *shape = get_shape(i); - Transform2D mtx = get_shape_transform(i); - Vector2 scale = mtx.get_scale(); - inertia += shape->get_moment_of_inertia(mass, scale) + mass * mtx.get_origin().length_squared(); + real_t area = get_shape_aabb(i).get_area(); + if (area == 0.0) { + continue; + } + + real_t mass = area * this->mass / total_area; + + Transform2D mtx = get_shape_transform(i); + Vector2 scale = mtx.get_scale(); + Vector2 shape_origin = mtx.get_origin() - center_of_mass_local; + inertia += shape->get_moment_of_inertia(mass, scale) + mass * shape_origin.length_squared(); + } } - _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0; + _inv_inertia = inertia > 0.0 ? (1.0 / inertia) : 0.0; if (mass) { _inv_mass = 1.0 / mass; @@ -88,18 +113,23 @@ void Body2DSW::update_inertias() { _inv_inertia = 0; _inv_mass = 0; } break; - case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: { + case PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR: { _inv_inertia = 0; _inv_mass = 1.0 / mass; } break; } - //_update_inertia_tensor(); - //_update_shapes(); + _update_transform_dependent(); } -void Body2DSW::set_active(bool p_active) { +void GodotBody2D::reset_mass_properties() { + calculate_inertia = true; + calculate_center_of_mass = true; + _mass_properties_changed(); +} + +void GodotBody2D::set_active(bool p_active) { if (active == p_active) { return; } @@ -118,7 +148,7 @@ void Body2DSW::set_active(bool p_active) { } } -void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) { +void GodotBody2D::set_param(PhysicsServer2D::BodyParameter p_param, const Variant &p_value) { switch (p_param) { case PhysicsServer2D::BODY_PARAM_BOUNCE: { bounce = p_value; @@ -127,24 +157,47 @@ void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) friction = p_value; } break; case PhysicsServer2D::BODY_PARAM_MASS: { - ERR_FAIL_COND(p_value <= 0); - mass = p_value; - _update_inertia(); - + real_t mass_value = p_value; + ERR_FAIL_COND(mass_value <= 0); + mass = mass_value; + if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC) { + _mass_properties_changed(); + } } break; case PhysicsServer2D::BODY_PARAM_INERTIA: { - if (p_value <= 0) { - user_inertia = false; - _update_inertia(); + real_t inertia_value = p_value; + if (inertia_value <= 0.0) { + calculate_inertia = true; + if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) { + _mass_properties_changed(); + } } else { - user_inertia = true; - inertia = p_value; - _inv_inertia = 1.0 / p_value; + calculate_inertia = false; + inertia = inertia_value; + if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC) { + _inv_inertia = 1.0 / inertia; + } } } break; + case PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS: { + calculate_center_of_mass = false; + center_of_mass_local = p_value; + _update_transform_dependent(); + } break; case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: { + if (Math::is_zero_approx(gravity_scale)) { + wakeup(); + } gravity_scale = p_value; } break; + case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP_MODE: { + int mode_value = p_value; + linear_damp_mode = (PhysicsServer2D::BodyDampMode)mode_value; + } break; + case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP_MODE: { + int mode_value = p_value; + angular_damp_mode = (PhysicsServer2D::BodyDampMode)mode_value; + } break; case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP: { linear_damp = p_value; } break; @@ -156,7 +209,7 @@ void Body2DSW::set_param(PhysicsServer2D::BodyParameter p_param, real_t p_value) } } -real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const { +Variant GodotBody2D::get_param(PhysicsServer2D::BodyParameter p_param) const { switch (p_param) { case PhysicsServer2D::BODY_PARAM_BOUNCE: { return bounce; @@ -170,9 +223,18 @@ real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const { case PhysicsServer2D::BODY_PARAM_INERTIA: { return inertia; } + case PhysicsServer2D::BODY_PARAM_CENTER_OF_MASS: { + return center_of_mass_local; + } case PhysicsServer2D::BODY_PARAM_GRAVITY_SCALE: { return gravity_scale; } + case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP_MODE: { + return linear_damp_mode; + } + case PhysicsServer2D::BODY_PARAM_ANGULAR_DAMP_MODE: { + return angular_damp_mode; + } case PhysicsServer2D::BODY_PARAM_LINEAR_DAMP: { return linear_damp; } @@ -186,7 +248,7 @@ real_t Body2DSW::get_param(PhysicsServer2D::BodyParameter p_param) const { return 0; } -void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) { +void GodotBody2D::set_mode(PhysicsServer2D::BodyMode p_mode) { PhysicsServer2D::BodyMode prev = mode; mode = p_mode; @@ -207,38 +269,35 @@ void Body2DSW::set_mode(PhysicsServer2D::BodyMode p_mode) { } break; case PhysicsServer2D::BODY_MODE_DYNAMIC: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; - _inv_inertia = inertia > 0 ? (1.0 / inertia) : 0; + if (!calculate_inertia) { + _inv_inertia = 1.0 / inertia; + } + _mass_properties_changed(); _set_static(false); set_active(true); } break; - case PhysicsServer2D::BODY_MODE_DYNAMIC_LOCKED: { + case PhysicsServer2D::BODY_MODE_DYNAMIC_LINEAR: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; _inv_inertia = 0; + angular_velocity = 0; _set_static(false); set_active(true); - angular_velocity = 0; - } break; - } - if (p_mode == PhysicsServer2D::BODY_MODE_DYNAMIC && _inv_inertia == 0) { - _update_inertia(); + } } - /* - if (get_space()) - _update_queries(); - */ } -PhysicsServer2D::BodyMode Body2DSW::get_mode() const { +PhysicsServer2D::BodyMode GodotBody2D::get_mode() const { return mode; } -void Body2DSW::_shapes_changed() { - _update_inertia(); +void GodotBody2D::_shapes_changed() { + _mass_properties_changed(); + wakeup(); wakeup_neighbours(); } -void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_variant) { +void GodotBody2D::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_variant) { switch (p_state) { case PhysicsServer2D::BODY_STATE_TRANSFORM: { if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) { @@ -263,17 +322,20 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va } _set_transform(t); _set_inv_transform(get_transform().inverse()); + _update_transform_dependent(); } wakeup(); } break; case PhysicsServer2D::BODY_STATE_LINEAR_VELOCITY: { linear_velocity = p_variant; + constant_linear_velocity = linear_velocity; wakeup(); } break; case PhysicsServer2D::BODY_STATE_ANGULAR_VELOCITY: { angular_velocity = p_variant; + constant_angular_velocity = angular_velocity; wakeup(); } break; @@ -296,7 +358,7 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va } break; case PhysicsServer2D::BODY_STATE_CAN_SLEEP: { can_sleep = p_variant; - if (mode == PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) { + if (mode >= PhysicsServer2D::BODY_MODE_DYNAMIC && !active && !can_sleep) { set_active(true); } @@ -304,7 +366,7 @@ void Body2DSW::set_state(PhysicsServer2D::BodyState p_state, const Variant &p_va } } -Variant Body2DSW::get_state(PhysicsServer2D::BodyState p_state) const { +Variant GodotBody2D::get_state(PhysicsServer2D::BodyState p_state) const { switch (p_state) { case PhysicsServer2D::BODY_STATE_TRANSFORM: { return get_transform(); @@ -326,12 +388,12 @@ Variant Body2DSW::get_state(PhysicsServer2D::BodyState p_state) const { return Variant(); } -void Body2DSW::set_space(Space2DSW *p_space) { +void GodotBody2D::set_space(GodotSpace2D *p_space) { if (get_space()) { wakeup_neighbours(); - if (inertia_update_list.in_list()) { - get_space()->body_remove_from_inertia_update_list(&inertia_update_list); + if (mass_properties_update_list.in_list()) { + get_space()->body_remove_from_mass_properties_update_list(&mass_properties_update_list); } if (active_list.in_list()) { get_space()->body_remove_from_active_list(&active_list); @@ -344,84 +406,148 @@ void Body2DSW::set_space(Space2DSW *p_space) { _set_space(p_space); if (get_space()) { - _update_inertia(); + _mass_properties_changed(); if (active) { get_space()->body_add_to_active_list(&active_list); } } - - first_integration = false; } -void Body2DSW::_compute_area_gravity_and_damping(const Area2DSW *p_area) { - Vector2 area_gravity; - p_area->compute_gravity(get_transform().get_origin(), area_gravity); - gravity += area_gravity; - - area_linear_damp += p_area->get_linear_damp(); - area_angular_damp += p_area->get_angular_damp(); +void GodotBody2D::_update_transform_dependent() { + center_of_mass = get_transform().basis_xform(center_of_mass_local); } -void Body2DSW::integrate_forces(real_t p_step) { +void GodotBody2D::integrate_forces(real_t p_step) { if (mode == PhysicsServer2D::BODY_MODE_STATIC) { return; } - Area2DSW *def_area = get_space()->get_default_area(); - // Area2DSW *damp_area = def_area; - ERR_FAIL_COND(!def_area); + ERR_FAIL_COND(!get_space()); int ac = areas.size(); + + bool gravity_done = false; + bool linear_damp_done = false; + bool angular_damp_done = false; + bool stopped = false; + gravity = Vector2(0, 0); - area_angular_damp = 0; - area_linear_damp = 0; + + total_linear_damp = 0.0; + total_angular_damp = 0.0; + + // Combine gravity and damping from overlapping areas in priority order. if (ac) { areas.sort(); const AreaCMP *aa = &areas[0]; - // damp_area = aa[ac-1].area; for (int i = ac - 1; i >= 0 && !stopped; i--) { - PhysicsServer2D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode(); - switch (mode) { - case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE: - case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { - _compute_area_gravity_and_damping(aa[i].area); - stopped = mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; - } break; - case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE: - case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { - gravity = Vector2(0, 0); - area_angular_damp = 0; - area_linear_damp = 0; - _compute_area_gravity_and_damping(aa[i].area); - stopped = mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE; - } break; - default: { + if (!gravity_done) { + PhysicsServer2D::AreaSpaceOverrideMode area_gravity_mode = (PhysicsServer2D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer2D::AREA_PARAM_GRAVITY_OVERRIDE_MODE); + if (area_gravity_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + Vector2 area_gravity; + aa[i].area->compute_gravity(get_transform().get_origin(), area_gravity); + switch (area_gravity_mode) { + case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + gravity += area_gravity; + gravity_done = area_gravity_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + gravity = area_gravity; + gravity_done = area_gravity_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } } } + if (!linear_damp_done) { + PhysicsServer2D::AreaSpaceOverrideMode area_linear_damp_mode = (PhysicsServer2D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer2D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE); + if (area_linear_damp_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + real_t area_linear_damp = aa[i].area->get_linear_damp(); + switch (area_linear_damp_mode) { + case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + total_linear_damp += area_linear_damp; + linear_damp_done = area_linear_damp_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + total_linear_damp = area_linear_damp; + linear_damp_done = area_linear_damp_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } + } + } + if (!angular_damp_done) { + PhysicsServer2D::AreaSpaceOverrideMode area_angular_damp_mode = (PhysicsServer2D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer2D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE); + if (area_angular_damp_mode != PhysicsServer2D::AREA_SPACE_OVERRIDE_DISABLED) { + real_t area_angular_damp = aa[i].area->get_angular_damp(); + switch (area_angular_damp_mode) { + case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + total_angular_damp += area_angular_damp; + angular_damp_done = area_angular_damp_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + total_angular_damp = area_angular_damp; + angular_damp_done = area_angular_damp_mode == PhysicsServer2D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } + } + } + stopped = gravity_done && linear_damp_done && angular_damp_done; } } + + // Add default gravity and damping from space area. if (!stopped) { - _compute_area_gravity_and_damping(def_area); + GodotArea2D *default_area = get_space()->get_default_area(); + ERR_FAIL_COND(!default_area); + + if (!gravity_done) { + Vector2 default_gravity; + default_area->compute_gravity(get_transform().get_origin(), default_gravity); + gravity += default_gravity; + } + + if (!linear_damp_done) { + total_linear_damp += default_area->get_linear_damp(); + } + + if (!angular_damp_done) { + total_angular_damp += default_area->get_angular_damp(); + } } - gravity *= gravity_scale; - // If less than 0, override dampenings with that of the Body2D - if (angular_damp >= 0) { - area_angular_damp = angular_damp; + // Override linear damping with body's value. + switch (linear_damp_mode) { + case PhysicsServer2D::BODY_DAMP_MODE_COMBINE: { + total_linear_damp += linear_damp; + } break; + case PhysicsServer2D::BODY_DAMP_MODE_REPLACE: { + total_linear_damp = linear_damp; + } break; } - /* - else - area_angular_damp=damp_area->get_angular_damp(); - */ - if (linear_damp >= 0) { - area_linear_damp = linear_damp; + // Override angular damping with body's value. + switch (angular_damp_mode) { + case PhysicsServer2D::BODY_DAMP_MODE_COMBINE: { + total_angular_damp += angular_damp; + } break; + case PhysicsServer2D::BODY_DAMP_MODE_REPLACE: { + total_angular_damp = angular_damp; + } break; } - /* - else - area_linear_damp=damp_area->get_linear_damp(); - */ + + gravity *= gravity_scale; Vector2 motion; bool do_motion = false; @@ -429,35 +555,28 @@ void Body2DSW::integrate_forces(real_t p_step) { if (mode == PhysicsServer2D::BODY_MODE_KINEMATIC) { //compute motion, angular and etc. velocities from prev transform motion = new_transform.get_origin() - get_transform().get_origin(); - linear_velocity = motion / p_step; + linear_velocity = constant_linear_velocity + motion / p_step; real_t rot = new_transform.get_rotation() - get_transform().get_rotation(); - angular_velocity = remainder(rot, 2.0 * Math_PI) / p_step; + angular_velocity = constant_angular_velocity + remainder(rot, 2.0 * Math_PI) / p_step; do_motion = true; - /* - for(int i=0;i<get_shape_count();i++) { - set_shape_kinematic_advance(i,Vector2()); - set_shape_kinematic_retreat(i,0); - } - */ - } else { - if (!omit_force_integration && !first_integration) { + if (!omit_force_integration) { //overridden by direct state query Vector2 force = gravity * mass; force += applied_force; real_t torque = applied_torque; - real_t damp = 1.0 - p_step * area_linear_damp; + real_t damp = 1.0 - p_step * total_linear_damp; if (damp < 0) { // reached zero in the given time damp = 0; } - real_t angular_damp = 1.0 - p_step * area_angular_damp; + real_t angular_damp = 1.0 - p_step * total_angular_damp; if (angular_damp < 0) { // reached zero in the given time angular_damp = 0; @@ -476,9 +595,6 @@ void Body2DSW::integrate_forces(real_t p_step) { } } - //motion=linear_velocity*p_step; - - first_integration = false; biased_angular_velocity = 0; biased_linear_velocity = Vector2(); @@ -486,12 +602,10 @@ void Body2DSW::integrate_forces(real_t p_step) { _update_shapes_with_motion(motion); } - // damp_area=nullptr; // clear the area, so it is set in the next frame - def_area = nullptr; // clear the area, so it is set in the next frame contact_count = 0; } -void Body2DSW::integrate_velocities(real_t p_step) { +void GodotBody2D::integrate_velocities(real_t p_step) { if (mode == PhysicsServer2D::BODY_MODE_STATIC) { return; } @@ -512,9 +626,15 @@ void Body2DSW::integrate_velocities(real_t p_step) { real_t total_angular_velocity = angular_velocity + biased_angular_velocity; Vector2 total_linear_velocity = linear_velocity + biased_linear_velocity; - real_t angle = get_transform().get_rotation() + total_angular_velocity * p_step; + real_t angle_delta = total_angular_velocity * p_step; + real_t angle = get_transform().get_rotation() + angle_delta; Vector2 pos = get_transform().get_origin() + total_linear_velocity * p_step; + if (center_of_mass.length_squared() > CMP_EPSILON2) { + // Calculate displacement due to center of mass offset. + pos += center_of_mass - center_of_mass.rotated(angle_delta); + } + _set_transform(Transform2D(angle, pos), continuous_cd_mode == PhysicsServer2D::CCD_MODE_DISABLED); _set_inv_transform(get_transform().inverse()); @@ -522,21 +642,21 @@ void Body2DSW::integrate_velocities(real_t p_step) { new_transform = get_transform(); } - //_update_inertia_tensor(); + _update_transform_dependent(); } -void Body2DSW::wakeup_neighbours() { - for (const Pair<Constraint2DSW *, int> &E : constraint_list) { - const Constraint2DSW *c = E.first; - Body2DSW **n = c->get_body_ptr(); +void GodotBody2D::wakeup_neighbours() { + for (const Pair<GodotConstraint2D *, int> &E : constraint_list) { + const GodotConstraint2D *c = E.first; + GodotBody2D **n = c->get_body_ptr(); int bc = c->get_body_count(); for (int i = 0; i < bc; i++) { if (i == E.second) { continue; } - Body2DSW *b = n[i]; - if (b->mode != PhysicsServer2D::BODY_MODE_DYNAMIC) { + GodotBody2D *b = n[i]; + if (b->mode < PhysicsServer2D::BODY_MODE_DYNAMIC) { continue; } @@ -547,7 +667,7 @@ void Body2DSW::wakeup_neighbours() { } } -void Body2DSW::call_queries() { +void GodotBody2D::call_queries() { if (fi_callback_data) { if (!fi_callback_data->callable.get_object()) { set_force_integration_callback(Callable()); @@ -571,7 +691,7 @@ void Body2DSW::call_queries() { } } -bool Body2DSW::sleep_test(real_t p_step) { +bool GodotBody2D::sleep_test(real_t p_step) { if (mode == PhysicsServer2D::BODY_MODE_STATIC || mode == PhysicsServer2D::BODY_MODE_KINEMATIC) { return true; } else if (!can_sleep) { @@ -588,12 +708,12 @@ bool Body2DSW::sleep_test(real_t p_step) { } } -void Body2DSW::set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback) { +void GodotBody2D::set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback) { body_state_callback_instance = p_instance; body_state_callback = p_callback; } -void Body2DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { +void GodotBody2D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { if (p_callable.get_object()) { if (!fi_callback_data) { fi_callback_data = memnew(ForceIntegrationCallbackData); @@ -606,49 +726,23 @@ void Body2DSW::set_force_integration_callback(const Callable &p_callable, const } } -PhysicsDirectBodyState2DSW *Body2DSW::get_direct_state() { +GodotPhysicsDirectBodyState2D *GodotBody2D::get_direct_state() { if (!direct_state) { - direct_state = memnew(PhysicsDirectBodyState2DSW); + direct_state = memnew(GodotPhysicsDirectBodyState2D); direct_state->body = this; } return direct_state; } -Body2DSW::Body2DSW() : - CollisionObject2DSW(TYPE_BODY), +GodotBody2D::GodotBody2D() : + GodotCollisionObject2D(TYPE_BODY), active_list(this), - inertia_update_list(this), + mass_properties_update_list(this), direct_state_query_list(this) { - mode = PhysicsServer2D::BODY_MODE_DYNAMIC; - active = true; - angular_velocity = 0; - biased_angular_velocity = 0; - mass = 1; - inertia = 0; - user_inertia = false; - _inv_inertia = 0; - _inv_mass = 1; - bounce = 0; - friction = 1; - omit_force_integration = false; - applied_torque = 0; - island_step = 0; _set_static(false); - first_time_kinematic = false; - linear_damp = -1; - angular_damp = -1; - area_angular_damp = 0; - area_linear_damp = 0; - contact_count = 0; - gravity_scale = 1.0; - first_integration = false; - - still_time = 0; - continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED; - can_sleep = true; } -Body2DSW::~Body2DSW() { +GodotBody2D::~GodotBody2D() { if (fi_callback_data) { memdelete(fi_callback_data); } diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/godot_body_2d.h index 9cd53ceca1..0df93482dc 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/godot_body_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_2d_sw.h */ +/* godot_body_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,73 +28,87 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BODY_2D_SW_H -#define BODY_2D_SW_H +#ifndef GODOT_BODY_2D_H +#define GODOT_BODY_2D_H + +#include "godot_area_2d.h" +#include "godot_collision_object_2d.h" -#include "area_2d_sw.h" -#include "collision_object_2d_sw.h" #include "core/templates/list.h" #include "core/templates/pair.h" #include "core/templates/vset.h" -class Constraint2DSW; -class PhysicsDirectBodyState2DSW; +class GodotConstraint2D; +class GodotPhysicsDirectBodyState2D; -class Body2DSW : public CollisionObject2DSW { - PhysicsServer2D::BodyMode mode; +class GodotBody2D : public GodotCollisionObject2D { + PhysicsServer2D::BodyMode mode = PhysicsServer2D::BODY_MODE_DYNAMIC; Vector2 biased_linear_velocity; - real_t biased_angular_velocity; + real_t biased_angular_velocity = 0.0; Vector2 linear_velocity; - real_t angular_velocity; + real_t angular_velocity = 0.0; + + Vector2 constant_linear_velocity; + real_t constant_angular_velocity = 0.0; + + PhysicsServer2D::BodyDampMode linear_damp_mode = PhysicsServer2D::BODY_DAMP_MODE_COMBINE; + PhysicsServer2D::BodyDampMode angular_damp_mode = PhysicsServer2D::BODY_DAMP_MODE_COMBINE; + + real_t linear_damp = 0.0; + real_t angular_damp = 0.0; + + real_t total_linear_damp = 0.0; + real_t total_angular_damp = 0.0; + + real_t gravity_scale = 1.0; + + real_t bounce = 0.0; + real_t friction = 1.0; + + real_t mass = 1.0; + real_t _inv_mass = 1.0; - real_t linear_damp; - real_t angular_damp; - real_t gravity_scale; + real_t inertia = 0.0; + real_t _inv_inertia = 0.0; - real_t mass; - real_t inertia; - real_t bounce; - real_t friction; + Vector2 center_of_mass_local; + Vector2 center_of_mass; - real_t _inv_mass; - real_t _inv_inertia; - bool user_inertia; + bool calculate_inertia = true; + bool calculate_center_of_mass = true; Vector2 gravity; - real_t area_linear_damp; - real_t area_angular_damp; - real_t still_time; + real_t still_time = 0.0; Vector2 applied_force; - real_t applied_torque; + real_t applied_torque = 0.0; - SelfList<Body2DSW> active_list; - SelfList<Body2DSW> inertia_update_list; - SelfList<Body2DSW> direct_state_query_list; + SelfList<GodotBody2D> active_list; + SelfList<GodotBody2D> mass_properties_update_list; + SelfList<GodotBody2D> direct_state_query_list; VSet<RID> exceptions; - PhysicsServer2D::CCDMode continuous_cd_mode; - bool omit_force_integration; - bool active; - bool can_sleep; - bool first_time_kinematic; - bool first_integration; - void _update_inertia(); + PhysicsServer2D::CCDMode continuous_cd_mode = PhysicsServer2D::CCD_MODE_DISABLED; + bool omit_force_integration = false; + bool active = true; + bool can_sleep = true; + bool first_time_kinematic = false; + void _mass_properties_changed(); virtual void _shapes_changed(); Transform2D new_transform; - List<Pair<Constraint2DSW *, int>> constraint_list; + List<Pair<GodotConstraint2D *, int>> constraint_list; struct AreaCMP { - Area2DSW *area; - int refCount; + GodotArea2D *area = nullptr; + int refCount = 0; _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); } _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); } _FORCE_INLINE_ AreaCMP() {} - _FORCE_INLINE_ AreaCMP(Area2DSW *p_area) { + _FORCE_INLINE_ AreaCMP(GodotArea2D *p_area) { area = p_area; refCount = 1; } @@ -105,17 +119,17 @@ class Body2DSW : public CollisionObject2DSW { struct Contact { Vector2 local_pos; Vector2 local_normal; - real_t depth; - int local_shape; + real_t depth = 0.0; + int local_shape = 0; Vector2 collider_pos; - int collider_shape; + int collider_shape = 0; ObjectID collider_instance_id; RID collider; Vector2 collider_velocity_at_pos; }; Vector<Contact> contacts; //no contacts by default - int contact_count; + int contact_count = 0; void *body_state_callback_instance = nullptr; PhysicsServer2D::BodyStateCallback body_state_callback = nullptr; @@ -127,21 +141,21 @@ class Body2DSW : public CollisionObject2DSW { ForceIntegrationCallbackData *fi_callback_data = nullptr; - PhysicsDirectBodyState2DSW *direct_state = nullptr; + GodotPhysicsDirectBodyState2D *direct_state = nullptr; - uint64_t island_step; + uint64_t island_step = 0; - _FORCE_INLINE_ void _compute_area_gravity_and_damping(const Area2DSW *p_area); + void _update_transform_dependent(); - friend class PhysicsDirectBodyState2DSW; // i give up, too many functions to expose + friend class GodotPhysicsDirectBodyState2D; // i give up, too many functions to expose public: void set_state_sync_callback(void *p_instance, PhysicsServer2D::BodyStateCallback p_callback); void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant()); - PhysicsDirectBodyState2DSW *get_direct_state(); + GodotPhysicsDirectBodyState2D *get_direct_state(); - _FORCE_INLINE_ void add_area(Area2DSW *p_area) { + _FORCE_INLINE_ void add_area(GodotArea2D *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { areas.write[index].refCount += 1; @@ -150,12 +164,12 @@ public: } } - _FORCE_INLINE_ void remove_area(Area2DSW *p_area) { + _FORCE_INLINE_ void remove_area(GodotArea2D *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { areas.write[index].refCount -= 1; if (areas[index].refCount < 1) { - areas.remove(index); + areas.remove_at(index); } } } @@ -181,9 +195,9 @@ public: _FORCE_INLINE_ uint64_t get_island_step() const { return island_step; } _FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; } - _FORCE_INLINE_ void add_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); } - _FORCE_INLINE_ void remove_constraint(Constraint2DSW *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); } - const List<Pair<Constraint2DSW *, int>> &get_constraint_list() const { return constraint_list; } + _FORCE_INLINE_ void add_constraint(GodotConstraint2D *p_constraint, int p_pos) { constraint_list.push_back({ p_constraint, p_pos }); } + _FORCE_INLINE_ void remove_constraint(GodotConstraint2D *p_constraint, int p_pos) { constraint_list.erase({ p_constraint, p_pos }); } + const List<Pair<GodotConstraint2D *, int>> &get_constraint_list() const { return constraint_list; } _FORCE_INLINE_ void clear_constraint_list() { constraint_list.clear(); } _FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; } @@ -207,7 +221,7 @@ public: _FORCE_INLINE_ void apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) { linear_velocity += p_impulse * _inv_mass; - angular_velocity += _inv_inertia * p_position.cross(p_impulse); + angular_velocity += _inv_inertia * (p_position - center_of_mass).cross(p_impulse); } _FORCE_INLINE_ void apply_torque_impulse(real_t p_torque) { @@ -216,7 +230,7 @@ public: _FORCE_INLINE_ void apply_bias_impulse(const Vector2 &p_impulse, const Vector2 &p_position = Vector2()) { biased_linear_velocity += p_impulse * _inv_mass; - biased_angular_velocity += _inv_inertia * p_position.cross(p_impulse); + biased_angular_velocity += _inv_inertia * (p_position - center_of_mass).cross(p_impulse); } void set_active(bool p_active); @@ -229,8 +243,8 @@ public: set_active(true); } - void set_param(PhysicsServer2D::BodyParameter p_param, real_t); - real_t get_param(PhysicsServer2D::BodyParameter p_param) const; + void set_param(PhysicsServer2D::BodyParameter p_param, const Variant &p_value); + Variant get_param(PhysicsServer2D::BodyParameter p_param) const; void set_mode(PhysicsServer2D::BodyMode p_mode); PhysicsServer2D::BodyMode get_mode() const; @@ -250,7 +264,7 @@ public: _FORCE_INLINE_ void add_force(const Vector2 &p_force, const Vector2 &p_position = Vector2()) { applied_force += p_force; - applied_torque += p_position.cross(p_force); + applied_torque += (p_position - center_of_mass).cross(p_force); } _FORCE_INLINE_ void add_torque(real_t p_torque) { @@ -260,17 +274,17 @@ public: _FORCE_INLINE_ void set_continuous_collision_detection_mode(PhysicsServer2D::CCDMode p_mode) { continuous_cd_mode = p_mode; } _FORCE_INLINE_ PhysicsServer2D::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; } - void set_space(Space2DSW *p_space); + void set_space(GodotSpace2D *p_space); - void update_inertias(); + void update_mass_properties(); + void reset_mass_properties(); + _FORCE_INLINE_ const Vector2 &get_center_of_mass() const { return center_of_mass; } + _FORCE_INLINE_ const Vector2 &get_center_of_mass_local() const { return center_of_mass_local; } _FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; } _FORCE_INLINE_ real_t get_inv_inertia() const { return _inv_inertia; } _FORCE_INLINE_ real_t get_friction() const { return friction; } - _FORCE_INLINE_ Vector2 get_gravity() const { return gravity; } _FORCE_INLINE_ real_t get_bounce() const { return bounce; } - _FORCE_INLINE_ real_t get_linear_damp() const { return linear_damp; } - _FORCE_INLINE_ real_t get_angular_damp() const { return angular_damp; } void integrate_forces(real_t p_step); void integrate_velocities(real_t p_step); @@ -293,13 +307,13 @@ public: bool sleep_test(real_t p_step); - Body2DSW(); - ~Body2DSW(); + GodotBody2D(); + ~GodotBody2D(); }; //add contact inline -void Body2DSW::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos) { +void GodotBody2D::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_normal, real_t p_depth, int p_local_shape, const Vector2 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector2 &p_collider_velocity_at_pos) { int c_max = contacts.size(); if (c_max == 0) { @@ -341,4 +355,4 @@ void Body2DSW::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_no c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos; } -#endif // BODY_2D_SW_H +#endif // GODOT_BODY_2D_H diff --git a/servers/physics_2d/body_direct_state_2d_sw.cpp b/servers/physics_2d/godot_body_direct_state_2d.cpp index 1f68cca843..9c9bd56268 100644 --- a/servers/physics_2d/body_direct_state_2d_sw.cpp +++ b/servers/physics_2d/godot_body_direct_state_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_direct_state_2d_sw.cpp */ +/* godot_body_direct_state_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,155 +28,155 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "body_direct_state_2d_sw.h" +#include "godot_body_direct_state_2d.h" -#include "body_2d_sw.h" -#include "physics_server_2d_sw.h" -#include "space_2d_sw.h" +#include "godot_body_2d.h" +#include "godot_physics_server_2d.h" +#include "godot_space_2d.h" -Vector2 PhysicsDirectBodyState2DSW::get_total_gravity() const { +Vector2 GodotPhysicsDirectBodyState2D::get_total_gravity() const { return body->gravity; } -real_t PhysicsDirectBodyState2DSW::get_total_angular_damp() const { - return body->area_angular_damp; +real_t GodotPhysicsDirectBodyState2D::get_total_angular_damp() const { + return body->total_angular_damp; } -real_t PhysicsDirectBodyState2DSW::get_total_linear_damp() const { - return body->area_linear_damp; +real_t GodotPhysicsDirectBodyState2D::get_total_linear_damp() const { + return body->total_linear_damp; } -real_t PhysicsDirectBodyState2DSW::get_inverse_mass() const { +Vector2 GodotPhysicsDirectBodyState2D::get_center_of_mass() const { + return body->get_center_of_mass(); +} + +Vector2 GodotPhysicsDirectBodyState2D::get_center_of_mass_local() const { + return body->get_center_of_mass_local(); +} + +real_t GodotPhysicsDirectBodyState2D::get_inverse_mass() const { return body->get_inv_mass(); } -real_t PhysicsDirectBodyState2DSW::get_inverse_inertia() const { +real_t GodotPhysicsDirectBodyState2D::get_inverse_inertia() const { return body->get_inv_inertia(); } -void PhysicsDirectBodyState2DSW::set_linear_velocity(const Vector2 &p_velocity) { +void GodotPhysicsDirectBodyState2D::set_linear_velocity(const Vector2 &p_velocity) { + body->wakeup(); body->set_linear_velocity(p_velocity); } -Vector2 PhysicsDirectBodyState2DSW::get_linear_velocity() const { +Vector2 GodotPhysicsDirectBodyState2D::get_linear_velocity() const { return body->get_linear_velocity(); } -void PhysicsDirectBodyState2DSW::set_angular_velocity(real_t p_velocity) { +void GodotPhysicsDirectBodyState2D::set_angular_velocity(real_t p_velocity) { + body->wakeup(); body->set_angular_velocity(p_velocity); } -real_t PhysicsDirectBodyState2DSW::get_angular_velocity() const { +real_t GodotPhysicsDirectBodyState2D::get_angular_velocity() const { return body->get_angular_velocity(); } -void PhysicsDirectBodyState2DSW::set_transform(const Transform2D &p_transform) { +void GodotPhysicsDirectBodyState2D::set_transform(const Transform2D &p_transform) { body->set_state(PhysicsServer2D::BODY_STATE_TRANSFORM, p_transform); } -Transform2D PhysicsDirectBodyState2DSW::get_transform() const { +Transform2D GodotPhysicsDirectBodyState2D::get_transform() const { return body->get_transform(); } -Vector2 PhysicsDirectBodyState2DSW::get_velocity_at_local_position(const Vector2 &p_position) const { +Vector2 GodotPhysicsDirectBodyState2D::get_velocity_at_local_position(const Vector2 &p_position) const { return body->get_velocity_in_local_point(p_position); } -void PhysicsDirectBodyState2DSW::add_central_force(const Vector2 &p_force) { +void GodotPhysicsDirectBodyState2D::add_central_force(const Vector2 &p_force) { + body->wakeup(); body->add_central_force(p_force); } -void PhysicsDirectBodyState2DSW::add_force(const Vector2 &p_force, const Vector2 &p_position) { +void GodotPhysicsDirectBodyState2D::add_force(const Vector2 &p_force, const Vector2 &p_position) { + body->wakeup(); body->add_force(p_force, p_position); } -void PhysicsDirectBodyState2DSW::add_torque(real_t p_torque) { +void GodotPhysicsDirectBodyState2D::add_torque(real_t p_torque) { + body->wakeup(); body->add_torque(p_torque); } -void PhysicsDirectBodyState2DSW::apply_central_impulse(const Vector2 &p_impulse) { +void GodotPhysicsDirectBodyState2D::apply_central_impulse(const Vector2 &p_impulse) { + body->wakeup(); body->apply_central_impulse(p_impulse); } -void PhysicsDirectBodyState2DSW::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) { +void GodotPhysicsDirectBodyState2D::apply_impulse(const Vector2 &p_impulse, const Vector2 &p_position) { + body->wakeup(); body->apply_impulse(p_impulse, p_position); } -void PhysicsDirectBodyState2DSW::apply_torque_impulse(real_t p_torque) { +void GodotPhysicsDirectBodyState2D::apply_torque_impulse(real_t p_torque) { + body->wakeup(); body->apply_torque_impulse(p_torque); } -void PhysicsDirectBodyState2DSW::set_sleep_state(bool p_enable) { +void GodotPhysicsDirectBodyState2D::set_sleep_state(bool p_enable) { body->set_active(!p_enable); } -bool PhysicsDirectBodyState2DSW::is_sleeping() const { +bool GodotPhysicsDirectBodyState2D::is_sleeping() const { return !body->is_active(); } -int PhysicsDirectBodyState2DSW::get_contact_count() const { +int GodotPhysicsDirectBodyState2D::get_contact_count() const { return body->contact_count; } -Vector2 PhysicsDirectBodyState2DSW::get_contact_local_position(int p_contact_idx) const { +Vector2 GodotPhysicsDirectBodyState2D::get_contact_local_position(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2()); return body->contacts[p_contact_idx].local_pos; } -Vector2 PhysicsDirectBodyState2DSW::get_contact_local_normal(int p_contact_idx) const { +Vector2 GodotPhysicsDirectBodyState2D::get_contact_local_normal(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2()); return body->contacts[p_contact_idx].local_normal; } -int PhysicsDirectBodyState2DSW::get_contact_local_shape(int p_contact_idx) const { +int GodotPhysicsDirectBodyState2D::get_contact_local_shape(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1); return body->contacts[p_contact_idx].local_shape; } -RID PhysicsDirectBodyState2DSW::get_contact_collider(int p_contact_idx) const { +RID GodotPhysicsDirectBodyState2D::get_contact_collider(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID()); return body->contacts[p_contact_idx].collider; } -Vector2 PhysicsDirectBodyState2DSW::get_contact_collider_position(int p_contact_idx) const { +Vector2 GodotPhysicsDirectBodyState2D::get_contact_collider_position(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2()); return body->contacts[p_contact_idx].collider_pos; } -ObjectID PhysicsDirectBodyState2DSW::get_contact_collider_id(int p_contact_idx) const { +ObjectID GodotPhysicsDirectBodyState2D::get_contact_collider_id(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID()); return body->contacts[p_contact_idx].collider_instance_id; } -int PhysicsDirectBodyState2DSW::get_contact_collider_shape(int p_contact_idx) const { +int GodotPhysicsDirectBodyState2D::get_contact_collider_shape(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0); return body->contacts[p_contact_idx].collider_shape; } -Vector2 PhysicsDirectBodyState2DSW::get_contact_collider_velocity_at_position(int p_contact_idx) const { +Vector2 GodotPhysicsDirectBodyState2D::get_contact_collider_velocity_at_position(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector2()); return body->contacts[p_contact_idx].collider_velocity_at_pos; } -Variant PhysicsDirectBodyState2DSW::get_contact_collider_shape_metadata(int p_contact_idx) const { - ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Variant()); - - if (!PhysicsServer2DSW::singletonsw->body_owner.owns(body->contacts[p_contact_idx].collider)) { - return Variant(); - } - Body2DSW *other = PhysicsServer2DSW::singletonsw->body_owner.getornull(body->contacts[p_contact_idx].collider); - - int sidx = body->contacts[p_contact_idx].collider_shape; - if (sidx < 0 || sidx >= other->get_shape_count()) { - return Variant(); - } - - return other->get_shape_metadata(sidx); -} - -PhysicsDirectSpaceState2D *PhysicsDirectBodyState2DSW::get_space_state() { +PhysicsDirectSpaceState2D *GodotPhysicsDirectBodyState2D::get_space_state() { return body->get_space()->get_direct_state(); } -real_t PhysicsDirectBodyState2DSW::get_step() const { +real_t GodotPhysicsDirectBodyState2D::get_step() const { return body->get_space()->get_last_step(); } diff --git a/servers/physics_2d/body_direct_state_2d_sw.h b/servers/physics_2d/godot_body_direct_state_2d.h index aef9186086..ff25205d52 100644 --- a/servers/physics_2d/body_direct_state_2d_sw.h +++ b/servers/physics_2d/godot_body_direct_state_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_direct_state_2d_sw.h */ +/* godot_body_direct_state_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,23 +28,25 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BODY_DIRECT_STATE_2D_SW_H -#define BODY_DIRECT_STATE_2D_SW_H +#ifndef GODOT_BODY_DIRECT_STATE_2D_H +#define GODOT_BODY_DIRECT_STATE_2D_H #include "servers/physics_server_2d.h" -class Body2DSW; +class GodotBody2D; -class PhysicsDirectBodyState2DSW : public PhysicsDirectBodyState2D { - GDCLASS(PhysicsDirectBodyState2DSW, PhysicsDirectBodyState2D); +class GodotPhysicsDirectBodyState2D : public PhysicsDirectBodyState2D { + GDCLASS(GodotPhysicsDirectBodyState2D, PhysicsDirectBodyState2D); public: - Body2DSW *body = nullptr; + GodotBody2D *body = nullptr; virtual Vector2 get_total_gravity() const override; virtual real_t get_total_angular_damp() const override; virtual real_t get_total_linear_damp() const override; + virtual Vector2 get_center_of_mass() const override; + virtual Vector2 get_center_of_mass_local() const override; virtual real_t get_inverse_mass() const override; virtual real_t get_inverse_inertia() const override; @@ -79,7 +81,6 @@ public: virtual Vector2 get_contact_collider_position(int p_contact_idx) const override; virtual ObjectID get_contact_collider_id(int p_contact_idx) const override; virtual int get_contact_collider_shape(int p_contact_idx) const override; - virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const override; virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const override; @@ -88,4 +89,4 @@ public: virtual real_t get_step() const override; }; -#endif // BODY_2D_SW_H +#endif // GODOT_BODY_DIRECT_STATE_2D_H diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/godot_body_pair_2d.cpp index 8bcc4609f4..97eeefbfe6 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/godot_body_pair_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_pair_2d_sw.cpp */ +/* godot_body_pair_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "body_pair_2d_sw.h" -#include "collision_solver_2d_sw.h" -#include "space_2d_sw.h" +#include "godot_body_pair_2d.h" +#include "godot_collision_solver_2d.h" +#include "godot_space_2d.h" #define POSITION_CORRECTION #define ACCUMULATE_IMPULSES -void BodyPair2DSW::_add_contact(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_self) { - BodyPair2DSW *self = (BodyPair2DSW *)p_self; +void GodotBodyPair2D::_add_contact(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_self) { + GodotBodyPair2D *self = (GodotBodyPair2D *)p_self; self->_contact_added_callback(p_point_A, p_point_B); } -void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B) { +void GodotBodyPair2D::_contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B) { // check if we already have the contact Vector2 local_A = A->get_inv_transform().basis_xform(p_point_A); @@ -121,7 +121,7 @@ void BodyPair2DSW::_contact_added_callback(const Vector2 &p_point_A, const Vecto } } -void BodyPair2DSW::_validate_contacts() { +void GodotBodyPair2D::_validate_contacts() { //make sure to erase contacts that are no longer valid real_t max_separation = space->get_contact_max_separation(); @@ -164,7 +164,7 @@ void BodyPair2DSW::_validate_contacts() { } } -bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const Transform2D &p_xform_A, Body2DSW *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result) { +bool GodotBodyPair2D::_test_ccd(real_t p_step, GodotBody2D *p_A, int p_shape_A, const Transform2D &p_xform_A, GodotBody2D *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result) { Vector2 motion = p_A->get_linear_velocity() * p_step; real_t mlen = motion.length(); if (mlen < CMP_EPSILON) { @@ -217,15 +217,15 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const return true; } -real_t combine_bounce(Body2DSW *A, Body2DSW *B) { +real_t combine_bounce(GodotBody2D *A, GodotBody2D *B) { return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1); } -real_t combine_friction(Body2DSW *A, Body2DSW *B) { +real_t combine_friction(GodotBody2D *A, GodotBody2D *B) { return ABS(MIN(A->get_friction(), B->get_friction())); } -bool BodyPair2DSW::setup(real_t p_step) { +bool GodotBodyPair2D::setup(real_t p_step) { if (!A->interacts_with(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) { collided = false; return false; @@ -257,8 +257,8 @@ bool BodyPair2DSW::setup(real_t p_step) { xform_Bu.elements[2] -= offset_A; Transform2D xform_B = xform_Bu * B->get_shape_transform(shape_B); - Shape2DSW *shape_A_ptr = A->get_shape(shape_A); - Shape2DSW *shape_B_ptr = B->get_shape(shape_B); + GodotShape2D *shape_A_ptr = A->get_shape(shape_A); + GodotShape2D *shape_B_ptr = B->get_shape(shape_B); Vector2 motion_A, motion_B; @@ -271,7 +271,7 @@ bool BodyPair2DSW::setup(real_t p_step) { bool prev_collided = collided; - collided = CollisionSolver2DSW::solve(shape_A_ptr, xform_A, motion_A, shape_B_ptr, xform_B, motion_B, _add_contact, this, &sep_axis); + collided = GodotCollisionSolver2D::solve(shape_A_ptr, xform_A, motion_A, shape_B_ptr, xform_B, motion_B, _add_contact, this, &sep_axis); if (!collided) { //test ccd (currently just a raycast) @@ -344,7 +344,7 @@ bool BodyPair2DSW::setup(real_t p_step) { return true; } -bool BodyPair2DSW::pre_solve(real_t p_step) { +bool GodotBodyPair2D::pre_solve(real_t p_step) { if (!collided || oneway_disabled) { return false; } @@ -353,8 +353,8 @@ bool BodyPair2DSW::pre_solve(real_t p_step) { real_t bias = 0.3; - Shape2DSW *shape_A_ptr = A->get_shape(shape_A); - Shape2DSW *shape_B_ptr = B->get_shape(shape_B); + GodotShape2D *shape_A_ptr = A->get_shape(shape_A); + GodotShape2D *shape_B_ptr = B->get_shape(shape_B); if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) { if (shape_A_ptr->get_custom_bias() == 0) { @@ -466,7 +466,7 @@ bool BodyPair2DSW::pre_solve(real_t p_step) { return do_process; } -void BodyPair2DSW::solve(real_t p_step) { +void GodotBodyPair2D::solve(real_t p_step) { if (!collided || oneway_disabled) { return; } @@ -528,8 +528,8 @@ void BodyPair2DSW::solve(real_t p_step) { } } -BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_shape_B) : - Constraint2DSW(_arr, 2) { +GodotBodyPair2D::GodotBodyPair2D(GodotBody2D *p_A, int p_shape_A, GodotBody2D *p_B, int p_shape_B) : + GodotConstraint2D(_arr, 2) { A = p_A; B = p_B; shape_A = p_shape_A; @@ -539,7 +539,7 @@ BodyPair2DSW::BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_sh B->add_constraint(this, 1); } -BodyPair2DSW::~BodyPair2DSW() { +GodotBodyPair2D::~GodotBodyPair2D() { A->remove_constraint(this, 0); B->remove_constraint(this, 1); } diff --git a/servers/physics_2d/body_pair_2d_sw.h b/servers/physics_2d/godot_body_pair_2d.h index 849a7e2430..0938ab542b 100644 --- a/servers/physics_2d/body_pair_2d_sw.h +++ b/servers/physics_2d/godot_body_pair_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_pair_2d_sw.h */ +/* godot_body_pair_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,23 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BODY_PAIR_2D_SW_H -#define BODY_PAIR_2D_SW_H +#ifndef GODOT_BODY_PAIR_2D_H +#define GODOT_BODY_PAIR_2D_H -#include "body_2d_sw.h" -#include "constraint_2d_sw.h" +#include "godot_body_2d.h" +#include "godot_constraint_2d.h" -class BodyPair2DSW : public Constraint2DSW { +class GodotBodyPair2D : public GodotConstraint2D { enum { MAX_CONTACTS = 2 }; union { struct { - Body2DSW *A; - Body2DSW *B; + GodotBody2D *A; + GodotBody2D *B; }; - Body2DSW *_arr[2] = { nullptr, nullptr }; + GodotBody2D *_arr[2] = { nullptr, nullptr }; }; int shape_A = 0; @@ -53,23 +53,23 @@ class BodyPair2DSW : public Constraint2DSW { bool collide_A = false; bool collide_B = false; - Space2DSW *space = nullptr; + GodotSpace2D *space = nullptr; struct Contact { Vector2 position; Vector2 normal; Vector2 local_A, local_B; - real_t acc_normal_impulse; // accumulated normal impulse (Pn) - real_t acc_tangent_impulse; // accumulated tangent impulse (Pt) - real_t acc_bias_impulse; // accumulated normal impulse for position bias (Pnb) - real_t mass_normal, mass_tangent; - real_t bias; + real_t acc_normal_impulse = 0.0; // accumulated normal impulse (Pn) + real_t acc_tangent_impulse = 0.0; // accumulated tangent impulse (Pt) + real_t acc_bias_impulse = 0.0; // accumulated normal impulse for position bias (Pnb) + real_t mass_normal, mass_tangent = 0.0; + real_t bias = 0.0; - real_t depth; - bool active; + real_t depth = 0.0; + bool active = false; Vector2 rA, rB; - bool reused; - real_t bounce; + bool reused = false; + real_t bounce = 0.0; }; Vector2 offset_B; //use local A coordinates to avoid numerical issues on collision detection @@ -81,7 +81,7 @@ class BodyPair2DSW : public Constraint2DSW { bool oneway_disabled = false; bool report_contacts_only = false; - bool _test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const Transform2D &p_xform_A, Body2DSW *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result = false); + bool _test_ccd(real_t p_step, GodotBody2D *p_A, int p_shape_A, const Transform2D &p_xform_A, GodotBody2D *p_B, int p_shape_B, const Transform2D &p_xform_B, bool p_swap_result = false); void _validate_contacts(); static void _add_contact(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_self); _FORCE_INLINE_ void _contact_added_callback(const Vector2 &p_point_A, const Vector2 &p_point_B); @@ -91,8 +91,8 @@ public: virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - BodyPair2DSW(Body2DSW *p_A, int p_shape_A, Body2DSW *p_B, int p_shape_B); - ~BodyPair2DSW(); + GodotBodyPair2D(GodotBody2D *p_A, int p_shape_A, GodotBody2D *p_B, int p_shape_B); + ~GodotBodyPair2D(); }; -#endif // BODY_PAIR_2D_SW_H +#endif // GODOT_BODY_PAIR_2D_H diff --git a/servers/physics_2d/broad_phase_2d_sw.cpp b/servers/physics_2d/godot_broad_phase_2d.cpp index 7f0af48b1f..4b35f8d996 100644 --- a/servers/physics_2d/broad_phase_2d_sw.cpp +++ b/servers/physics_2d/godot_broad_phase_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_2d_sw.cpp */ +/* godot_broad_phase_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "broad_phase_2d_sw.h" +#include "godot_broad_phase_2d.h" -BroadPhase2DSW::CreateFunction BroadPhase2DSW::create_func = nullptr; +GodotBroadPhase2D::CreateFunction GodotBroadPhase2D::create_func = nullptr; -BroadPhase2DSW::~BroadPhase2DSW() { +GodotBroadPhase2D::~GodotBroadPhase2D() { } diff --git a/servers/physics_2d/broad_phase_2d_sw.h b/servers/physics_2d/godot_broad_phase_2d.h index 0f82f06b9c..7017a6e41f 100644 --- a/servers/physics_2d/broad_phase_2d_sw.h +++ b/servers/physics_2d/godot_broad_phase_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_2d_sw.h */ +/* godot_broad_phase_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,44 +28,44 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BROAD_PHASE_2D_SW_H -#define BROAD_PHASE_2D_SW_H +#ifndef GODOT_BROAD_PHASE_2D_H +#define GODOT_BROAD_PHASE_2D_H #include "core/math/math_funcs.h" #include "core/math/rect2.h" -class CollisionObject2DSW; +class GodotCollisionObject2D; -class BroadPhase2DSW { +class GodotBroadPhase2D { public: - typedef BroadPhase2DSW *(*CreateFunction)(); + typedef GodotBroadPhase2D *(*CreateFunction)(); static CreateFunction create_func; typedef uint32_t ID; - typedef void *(*PairCallback)(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_userdata); - typedef void (*UnpairCallback)(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_userdata); + typedef void *(*PairCallback)(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_userdata); + typedef void (*UnpairCallback)(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_data, void *p_userdata); // 0 is an invalid ID - virtual ID create(CollisionObject2DSW *p_object_, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false) = 0; + virtual ID create(GodotCollisionObject2D *p_object_, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false) = 0; virtual void move(ID p_id, const Rect2 &p_aabb) = 0; virtual void set_static(ID p_id, bool p_static) = 0; virtual void remove(ID p_id) = 0; - virtual CollisionObject2DSW *get_object(ID p_id) const = 0; + virtual GodotCollisionObject2D *get_object(ID p_id) const = 0; virtual bool is_static(ID p_id) const = 0; virtual int get_subindex(ID p_id) const = 0; - virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; - virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; + virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; + virtual int cull_aabb(const Rect2 &p_aabb, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata) = 0; virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) = 0; virtual void update() = 0; - virtual ~BroadPhase2DSW(); + virtual ~GodotBroadPhase2D(); }; -#endif // BROAD_PHASE_2D_SW_H +#endif // GODOT_BROAD_PHASE_2D_H diff --git a/servers/physics_2d/broad_phase_2d_bvh.cpp b/servers/physics_2d/godot_broad_phase_2d_bvh.cpp index 5f53f4a012..9ec6b0a6b7 100644 --- a/servers/physics_2d/broad_phase_2d_bvh.cpp +++ b/servers/physics_2d/godot_broad_phase_2d_bvh.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_2d_bvh.cpp */ +/* godot_broad_phase_2d_bvh.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,51 +28,51 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "broad_phase_2d_bvh.h" -#include "collision_object_2d_sw.h" +#include "godot_broad_phase_2d_bvh.h" +#include "godot_collision_object_2d.h" -BroadPhase2DSW::ID BroadPhase2DBVH::create(CollisionObject2DSW *p_object, int p_subindex, const Rect2 &p_aabb, bool p_static) { +GodotBroadPhase2D::ID GodotBroadPhase2DBVH::create(GodotCollisionObject2D *p_object, int p_subindex, const Rect2 &p_aabb, bool p_static) { ID oid = bvh.create(p_object, true, p_aabb, p_subindex, !p_static, 1 << p_object->get_type(), p_static ? 0 : 0xFFFFF); // Pair everything, don't care? return oid + 1; } -void BroadPhase2DBVH::move(ID p_id, const Rect2 &p_aabb) { +void GodotBroadPhase2DBVH::move(ID p_id, const Rect2 &p_aabb) { bvh.move(p_id - 1, p_aabb); } -void BroadPhase2DBVH::set_static(ID p_id, bool p_static) { - CollisionObject2DSW *it = bvh.get(p_id - 1); +void GodotBroadPhase2DBVH::set_static(ID p_id, bool p_static) { + GodotCollisionObject2D *it = bvh.get(p_id - 1); bvh.set_pairable(p_id - 1, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF, false); // Pair everything, don't care? } -void BroadPhase2DBVH::remove(ID p_id) { +void GodotBroadPhase2DBVH::remove(ID p_id) { bvh.erase(p_id - 1); } -CollisionObject2DSW *BroadPhase2DBVH::get_object(ID p_id) const { - CollisionObject2DSW *it = bvh.get(p_id - 1); +GodotCollisionObject2D *GodotBroadPhase2DBVH::get_object(ID p_id) const { + GodotCollisionObject2D *it = bvh.get(p_id - 1); ERR_FAIL_COND_V(!it, nullptr); return it; } -bool BroadPhase2DBVH::is_static(ID p_id) const { +bool GodotBroadPhase2DBVH::is_static(ID p_id) const { return !bvh.is_pairable(p_id - 1); } -int BroadPhase2DBVH::get_subindex(ID p_id) const { +int GodotBroadPhase2DBVH::get_subindex(ID p_id) const { return bvh.get_subindex(p_id - 1); } -int BroadPhase2DBVH::cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) { +int GodotBroadPhase2DBVH::cull_segment(const Vector2 &p_from, const Vector2 &p_to, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices) { return bvh.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices); } -int BroadPhase2DBVH::cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices) { +int GodotBroadPhase2DBVH::cull_aabb(const Rect2 &p_aabb, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices) { return bvh.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices); } -void *BroadPhase2DBVH::_pair_callback(void *self, uint32_t p_A, CollisionObject2DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject2DSW *p_object_B, int subindex_B) { - BroadPhase2DBVH *bpo = (BroadPhase2DBVH *)(self); +void *GodotBroadPhase2DBVH::_pair_callback(void *self, uint32_t p_A, GodotCollisionObject2D *p_object_A, int subindex_A, uint32_t p_B, GodotCollisionObject2D *p_object_B, int subindex_B) { + GodotBroadPhase2DBVH *bpo = (GodotBroadPhase2DBVH *)(self); if (!bpo->pair_callback) { return nullptr; } @@ -80,8 +80,8 @@ void *BroadPhase2DBVH::_pair_callback(void *self, uint32_t p_A, CollisionObject2 return bpo->pair_callback(p_object_A, subindex_A, p_object_B, subindex_B, bpo->pair_userdata); } -void BroadPhase2DBVH::_unpair_callback(void *self, uint32_t p_A, CollisionObject2DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject2DSW *p_object_B, int subindex_B, void *pairdata) { - BroadPhase2DBVH *bpo = (BroadPhase2DBVH *)(self); +void GodotBroadPhase2DBVH::_unpair_callback(void *self, uint32_t p_A, GodotCollisionObject2D *p_object_A, int subindex_A, uint32_t p_B, GodotCollisionObject2D *p_object_B, int subindex_B, void *pairdata) { + GodotBroadPhase2DBVH *bpo = (GodotBroadPhase2DBVH *)(self); if (!bpo->unpair_callback) { return; } @@ -89,28 +89,25 @@ void BroadPhase2DBVH::_unpair_callback(void *self, uint32_t p_A, CollisionObject bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata); } -void BroadPhase2DBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { +void GodotBroadPhase2DBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { pair_callback = p_pair_callback; pair_userdata = p_userdata; } -void BroadPhase2DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { +void GodotBroadPhase2DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { unpair_callback = p_unpair_callback; unpair_userdata = p_userdata; } -void BroadPhase2DBVH::update() { +void GodotBroadPhase2DBVH::update() { bvh.update(); } -BroadPhase2DSW *BroadPhase2DBVH::_create() { - return memnew(BroadPhase2DBVH); +GodotBroadPhase2D *GodotBroadPhase2DBVH::_create() { + return memnew(GodotBroadPhase2DBVH); } -BroadPhase2DBVH::BroadPhase2DBVH() { +GodotBroadPhase2DBVH::GodotBroadPhase2DBVH() { bvh.set_pair_callback(_pair_callback, this); bvh.set_unpair_callback(_unpair_callback, this); - pair_callback = nullptr; - pair_userdata = nullptr; - unpair_userdata = nullptr; } diff --git a/servers/physics_2d/broad_phase_2d_bvh.h b/servers/physics_2d/godot_broad_phase_2d_bvh.h index 6c11d2561b..19b49f3499 100644 --- a/servers/physics_2d/broad_phase_2d_bvh.h +++ b/servers/physics_2d/godot_broad_phase_2d_bvh.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_2d_bvh.h */ +/* godot_broad_phase_2d_bvh.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,46 +28,47 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BROAD_PHASE_2D_BVH_H -#define BROAD_PHASE_2D_BVH_H +#ifndef GODOT_BROAD_PHASE_2D_BVH_H +#define GODOT_BROAD_PHASE_2D_BVH_H + +#include "godot_broad_phase_2d.h" -#include "broad_phase_2d_sw.h" #include "core/math/bvh.h" #include "core/math/rect2.h" #include "core/math/vector2.h" -class BroadPhase2DBVH : public BroadPhase2DSW { - BVH_Manager<CollisionObject2DSW, true, 128, Rect2, Vector2> bvh; +class GodotBroadPhase2DBVH : public GodotBroadPhase2D { + BVH_Manager<GodotCollisionObject2D, true, 128, Rect2, Vector2> bvh; - static void *_pair_callback(void *, uint32_t, CollisionObject2DSW *, int, uint32_t, CollisionObject2DSW *, int); - static void _unpair_callback(void *, uint32_t, CollisionObject2DSW *, int, uint32_t, CollisionObject2DSW *, int, void *); + static void *_pair_callback(void *, uint32_t, GodotCollisionObject2D *, int, uint32_t, GodotCollisionObject2D *, int); + static void _unpair_callback(void *, uint32_t, GodotCollisionObject2D *, int, uint32_t, GodotCollisionObject2D *, int, void *); - PairCallback pair_callback; - void *pair_userdata; - UnpairCallback unpair_callback; - void *unpair_userdata; + PairCallback pair_callback = nullptr; + void *pair_userdata = nullptr; + UnpairCallback unpair_callback = nullptr; + void *unpair_userdata = nullptr; public: // 0 is an invalid ID - virtual ID create(CollisionObject2DSW *p_object, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false); + virtual ID create(GodotCollisionObject2D *p_object, int p_subindex = 0, const Rect2 &p_aabb = Rect2(), bool p_static = false); virtual void move(ID p_id, const Rect2 &p_aabb); virtual void set_static(ID p_id, bool p_static); virtual void remove(ID p_id); - virtual CollisionObject2DSW *get_object(ID p_id) const; + virtual GodotCollisionObject2D *get_object(ID p_id) const; virtual bool is_static(ID p_id) const; virtual int get_subindex(ID p_id) const; - virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr); - virtual int cull_aabb(const Rect2 &p_aabb, CollisionObject2DSW **p_results, int p_max_results, int *p_result_indices = nullptr); + virtual int cull_segment(const Vector2 &p_from, const Vector2 &p_to, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices = nullptr); + virtual int cull_aabb(const Rect2 &p_aabb, GodotCollisionObject2D **p_results, int p_max_results, int *p_result_indices = nullptr); virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata); virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata); virtual void update(); - static BroadPhase2DSW *_create(); - BroadPhase2DBVH(); + static GodotBroadPhase2D *_create(); + GodotBroadPhase2DBVH(); }; -#endif // BROAD_PHASE_2D_BVH_H +#endif // GODOT_BROAD_PHASE_2D_BVH_H diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/godot_collision_object_2d.cpp index 5d1ef83165..719d9c874a 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/godot_collision_object_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_object_2d_sw.cpp */ +/* godot_collision_object_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "collision_object_2d_sw.h" -#include "servers/physics_2d/physics_server_2d_sw.h" -#include "space_2d_sw.h" +#include "godot_collision_object_2d.h" +#include "godot_physics_server_2d.h" +#include "godot_space_2d.h" -void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_transform, bool p_disabled) { +void GodotCollisionObject2D::add_shape(GodotShape2D *p_shape, const Transform2D &p_transform, bool p_disabled) { Shape s; s.shape = p_shape; s.xform = p_transform; @@ -45,11 +45,11 @@ void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_tra p_shape->add_owner(this); if (!pending_shape_update_list.in_list()) { - PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } -void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { +void GodotCollisionObject2D::set_shape(int p_index, GodotShape2D *p_shape) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes[p_index].shape->remove_owner(this); shapes.write[p_index].shape = p_shape; @@ -57,30 +57,25 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { p_shape->add_owner(this); if (!pending_shape_update_list.in_list()) { - PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } -void CollisionObject2DSW::set_shape_metadata(int p_index, const Variant &p_metadata) { - ERR_FAIL_INDEX(p_index, shapes.size()); - shapes.write[p_index].metadata = p_metadata; -} - -void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_transform) { +void GodotCollisionObject2D::set_shape_transform(int p_index, const Transform2D &p_transform) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes.write[p_index].xform = p_transform; shapes.write[p_index].xform_inv = p_transform.affine_inverse(); if (!pending_shape_update_list.in_list()) { - PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } -void CollisionObject2DSW::set_shape_disabled(int p_idx, bool p_disabled) { +void GodotCollisionObject2D::set_shape_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, shapes.size()); - CollisionObject2DSW::Shape &shape = shapes.write[p_idx]; + GodotCollisionObject2D::Shape &shape = shapes.write[p_idx]; if (shape.disabled == p_disabled) { return; } @@ -95,16 +90,16 @@ void CollisionObject2DSW::set_shape_disabled(int p_idx, bool p_disabled) { space->get_broadphase()->remove(shape.bpid); shape.bpid = 0; if (!pending_shape_update_list.in_list()) { - PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } else if (!p_disabled && shape.bpid == 0) { if (!pending_shape_update_list.in_list()) { - PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } } -void CollisionObject2DSW::remove_shape(Shape2DSW *p_shape) { +void GodotCollisionObject2D::remove_shape(GodotShape2D *p_shape) { //remove a shape, all the times it appears for (int i = 0; i < shapes.size(); i++) { if (shapes[i].shape == p_shape) { @@ -114,7 +109,7 @@ void CollisionObject2DSW::remove_shape(Shape2DSW *p_shape) { } } -void CollisionObject2DSW::remove_shape(int p_index) { +void GodotCollisionObject2D::remove_shape(int p_index) { //remove anything from shape to be erased to end, so subindices don't change ERR_FAIL_INDEX(p_index, shapes.size()); for (int i = p_index; i < shapes.size(); i++) { @@ -126,16 +121,16 @@ void CollisionObject2DSW::remove_shape(int p_index) { shapes.write[i].bpid = 0; } shapes[p_index].shape->remove_owner(this); - shapes.remove(p_index); + shapes.remove_at(p_index); if (!pending_shape_update_list.in_list()) { - PhysicsServer2DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer2D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } // _update_shapes(); // _shapes_changed(); } -void CollisionObject2DSW::_set_static(bool p_static) { +void GodotCollisionObject2D::_set_static(bool p_static) { if (_static == p_static) { return; } @@ -152,7 +147,7 @@ void CollisionObject2DSW::_set_static(bool p_static) { } } -void CollisionObject2DSW::_unregister_shapes() { +void GodotCollisionObject2D::_unregister_shapes() { for (int i = 0; i < shapes.size(); i++) { Shape &s = shapes.write[i]; if (s.bpid > 0) { @@ -162,7 +157,7 @@ void CollisionObject2DSW::_unregister_shapes() { } } -void CollisionObject2DSW::_update_shapes() { +void GodotCollisionObject2D::_update_shapes() { if (!space) { return; } @@ -189,7 +184,7 @@ void CollisionObject2DSW::_update_shapes() { } } -void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) { +void GodotCollisionObject2D::_update_shapes_with_motion(const Vector2 &p_motion) { if (!space) { return; } @@ -216,7 +211,7 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) { } } -void CollisionObject2DSW::_set_space(Space2DSW *p_space) { +void GodotCollisionObject2D::_set_space(GodotSpace2D *p_space) { if (space) { space->remove_object(this); @@ -237,17 +232,12 @@ void CollisionObject2DSW::_set_space(Space2DSW *p_space) { } } -void CollisionObject2DSW::_shape_changed() { +void GodotCollisionObject2D::_shape_changed() { _update_shapes(); _shapes_changed(); } -CollisionObject2DSW::CollisionObject2DSW(Type p_type) : +GodotCollisionObject2D::GodotCollisionObject2D(Type p_type) : pending_shape_update_list(this) { - _static = true; type = p_type; - space = nullptr; - collision_mask = 1; - collision_layer = 1; - pickable = true; } diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/godot_collision_object_2d.h index 55ffa9b1b8..7233857808 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/godot_collision_object_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_object_2d_sw.h */ +/* godot_collision_object_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef COLLISION_OBJECT_2D_SW_H -#define COLLISION_OBJECT_2D_SW_H +#ifndef GODOT_COLLISION_OBJECT_2D_H +#define GODOT_COLLISION_OBJECT_2D_H + +#include "godot_broad_phase_2d.h" +#include "godot_shape_2d.h" -#include "broad_phase_2d_sw.h" #include "core/templates/self_list.h" #include "servers/physics_server_2d.h" -#include "shape_2d_sw.h" -class Space2DSW; +class GodotSpace2D; -class CollisionObject2DSW : public ShapeOwner2DSW { +class GodotCollisionObject2D : public GodotShapeOwner2D { public: enum Type { TYPE_AREA, @@ -50,34 +51,28 @@ private: RID self; ObjectID instance_id; ObjectID canvas_instance_id; - bool pickable; + bool pickable = true; struct Shape { Transform2D xform; Transform2D xform_inv; - BroadPhase2DSW::ID bpid; + GodotBroadPhase2D::ID bpid = 0; Rect2 aabb_cache; //for rayqueries - Shape2DSW *shape; - Variant metadata; - bool disabled; - bool one_way_collision; - real_t one_way_collision_margin; - Shape() { - disabled = false; - one_way_collision = false; - one_way_collision_margin = 0; - } + GodotShape2D *shape = nullptr; + bool disabled = false; + bool one_way_collision = false; + real_t one_way_collision_margin = 0.0; }; Vector<Shape> shapes; - Space2DSW *space; + GodotSpace2D *space = nullptr; Transform2D transform; Transform2D inv_transform; - uint32_t collision_mask; - uint32_t collision_layer; - bool _static; + uint32_t collision_mask = 1; + uint32_t collision_layer = 1; + bool _static = true; - SelfList<CollisionObject2DSW> pending_shape_update_list; + SelfList<GodotCollisionObject2D> pending_shape_update_list; void _update_shapes(); @@ -95,9 +90,9 @@ protected: void _set_static(bool p_static); virtual void _shapes_changed() = 0; - void _set_space(Space2DSW *p_space); + void _set_space(GodotSpace2D *p_space); - CollisionObject2DSW(Type p_type); + GodotCollisionObject2D(Type p_type); public: _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; } @@ -112,13 +107,12 @@ public: void _shape_changed(); _FORCE_INLINE_ Type get_type() const { return type; } - void add_shape(Shape2DSW *p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false); - void set_shape(int p_index, Shape2DSW *p_shape); + void add_shape(GodotShape2D *p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false); + void set_shape(int p_index, GodotShape2D *p_shape); void set_shape_transform(int p_index, const Transform2D &p_transform); - void set_shape_metadata(int p_index, const Variant &p_metadata); _FORCE_INLINE_ int get_shape_count() const { return shapes.size(); } - _FORCE_INLINE_ Shape2DSW *get_shape(int p_index) const { + _FORCE_INLINE_ GodotShape2D *get_shape(int p_index) const { CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].shape; } @@ -134,14 +128,10 @@ public: CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].aabb_cache; } - _FORCE_INLINE_ const Variant &get_shape_metadata(int p_index) const { - CRASH_BAD_INDEX(p_index, shapes.size()); - return shapes[p_index].metadata; - } _FORCE_INLINE_ const Transform2D &get_transform() const { return transform; } _FORCE_INLINE_ const Transform2D &get_inv_transform() const { return inv_transform; } - _FORCE_INLINE_ Space2DSW *get_space() const { return space; } + _FORCE_INLINE_ GodotSpace2D *get_space() const { return space; } void set_shape_disabled(int p_idx, bool p_disabled); _FORCE_INLINE_ bool is_shape_disabled(int p_idx) const { @@ -176,25 +166,25 @@ public: } _FORCE_INLINE_ uint32_t get_collision_layer() const { return collision_layer; } - void remove_shape(Shape2DSW *p_shape); + void remove_shape(GodotShape2D *p_shape); void remove_shape(int p_index); - virtual void set_space(Space2DSW *p_space) = 0; + virtual void set_space(GodotSpace2D *p_space) = 0; _FORCE_INLINE_ bool is_static() const { return _static; } void set_pickable(bool p_pickable) { pickable = p_pickable; } _FORCE_INLINE_ bool is_pickable() const { return pickable; } - _FORCE_INLINE_ bool collides_with(CollisionObject2DSW *p_other) const { + _FORCE_INLINE_ bool collides_with(GodotCollisionObject2D *p_other) const { return p_other->collision_layer & collision_mask; } - _FORCE_INLINE_ bool interacts_with(CollisionObject2DSW *p_other) const { + _FORCE_INLINE_ bool interacts_with(GodotCollisionObject2D *p_other) const { return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask; } - virtual ~CollisionObject2DSW() {} + virtual ~GodotCollisionObject2D() {} }; -#endif // COLLISION_OBJECT_2D_SW_H +#endif // GODOT_COLLISION_OBJECT_2D_H diff --git a/servers/physics_2d/collision_solver_2d_sw.cpp b/servers/physics_2d/godot_collision_solver_2d.cpp index ae50615953..25371b9885 100644 --- a/servers/physics_2d/collision_solver_2d_sw.cpp +++ b/servers/physics_2d/godot_collision_solver_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_solver_2d_sw.cpp */ +/* godot_collision_solver_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,20 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "collision_solver_2d_sw.h" -#include "collision_solver_2d_sat.h" +#include "godot_collision_solver_2d.h" +#include "godot_collision_solver_2d_sat.h" #define collision_solver sat_2d_calculate_penetration //#define collision_solver gjk_epa_calculate_penetration -bool CollisionSolver2DSW::solve_static_world_margin(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { - const WorldMarginShape2DSW *world_margin = static_cast<const WorldMarginShape2DSW *>(p_shape_A); - if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_MARGIN) { +bool GodotCollisionSolver2D::solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { + const GodotWorldBoundaryShape2D *world_boundary = static_cast<const GodotWorldBoundaryShape2D *>(p_shape_A); + if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) { return false; } - Vector2 n = p_transform_A.basis_xform(world_margin->get_normal()).normalized(); - Vector2 p = p_transform_A.xform(world_margin->get_normal() * world_margin->get_d()); + Vector2 n = p_transform_A.basis_xform(world_boundary->get_normal()).normalized(); + Vector2 p = p_transform_A.xform(world_boundary->get_normal() * world_boundary->get_d()); real_t d = n.dot(p); Vector2 supports[2]; @@ -73,8 +73,8 @@ bool CollisionSolver2DSW::solve_static_world_margin(const Shape2DSW *p_shape_A, return found; } -bool CollisionSolver2DSW::solve_separation_ray(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis, real_t p_margin) { - const SeparationRayShape2DSW *ray = static_cast<const SeparationRayShape2DSW *>(p_shape_A); +bool GodotCollisionSolver2D::solve_separation_ray(const GodotShape2D *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis, real_t p_margin) { + const GodotSeparationRayShape2D *ray = static_cast<const GodotSeparationRayShape2D *>(p_shape_A); if (p_shape_B->get_type() == PhysicsServer2D::SHAPE_SEPARATION_RAY) { return false; } @@ -133,23 +133,23 @@ bool CollisionSolver2DSW::solve_separation_ray(const Shape2DSW *p_shape_A, const } struct _ConcaveCollisionInfo2D { - const Transform2D *transform_A; - const Shape2DSW *shape_A; - const Transform2D *transform_B; + const Transform2D *transform_A = nullptr; + const GodotShape2D *shape_A = nullptr; + const Transform2D *transform_B = nullptr; Vector2 motion_A; Vector2 motion_B; - real_t margin_A; - real_t margin_B; - CollisionSolver2DSW::CallbackResult result_callback; - void *userdata; - bool swap_result; - bool collided; - int aabb_tests; - int collisions; - Vector2 *sep_axis; + real_t margin_A = 0.0; + real_t margin_B = 0.0; + GodotCollisionSolver2D::CallbackResult result_callback; + void *userdata = nullptr; + bool swap_result = false; + bool collided = false; + int aabb_tests = 0; + int collisions = 0; + Vector2 *sep_axis = nullptr; }; -bool CollisionSolver2DSW::concave_callback(void *p_userdata, Shape2DSW *p_convex) { +bool GodotCollisionSolver2D::concave_callback(void *p_userdata, GodotShape2D *p_convex) { _ConcaveCollisionInfo2D &cinfo = *(_ConcaveCollisionInfo2D *)(p_userdata); cinfo.aabb_tests++; @@ -165,8 +165,8 @@ bool CollisionSolver2DSW::concave_callback(void *p_userdata, Shape2DSW *p_convex return !cinfo.result_callback; } -bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) { - const ConcaveShape2DSW *concave_B = static_cast<const ConcaveShape2DSW *>(p_shape_B); +bool GodotCollisionSolver2D::solve_concave(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) { + const GodotConcaveShape2D *concave_B = static_cast<const GodotConcaveShape2D *>(p_shape_B); _ConcaveCollisionInfo2D cinfo; cinfo.transform_A = &p_transform_A; @@ -209,7 +209,7 @@ bool CollisionSolver2DSW::solve_concave(const Shape2DSW *p_shape_A, const Transf return cinfo.collided; } -bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) { +bool GodotCollisionSolver2D::solve(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) { PhysicsServer2D::ShapeType type_A = p_shape_A->get_type(); PhysicsServer2D::ShapeType type_B = p_shape_B->get_type(); bool concave_A = p_shape_A->is_concave(); @@ -225,15 +225,15 @@ bool CollisionSolver2DSW::solve(const Shape2DSW *p_shape_A, const Transform2D &p swap = true; } - if (type_A == PhysicsServer2D::SHAPE_WORLD_MARGIN) { - if (type_B == PhysicsServer2D::SHAPE_WORLD_MARGIN) { + if (type_A == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) { + if (type_B == PhysicsServer2D::SHAPE_WORLD_BOUNDARY) { return false; } if (swap) { - return solve_static_world_margin(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); + return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); } else { - return solve_static_world_margin(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); + return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); } } else if (type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY) { diff --git a/servers/physics_2d/collision_solver_2d_sw.h b/servers/physics_2d/godot_collision_solver_2d.h index 62fccc4ff3..f10815a444 100644 --- a/servers/physics_2d/collision_solver_2d_sw.h +++ b/servers/physics_2d/godot_collision_solver_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_solver_2d_sw.h */ +/* godot_collision_solver_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,23 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef COLLISION_SOLVER_2D_SW_H -#define COLLISION_SOLVER_2D_SW_H +#ifndef GODOT_COLLISION_SOLVER_2D_H +#define GODOT_COLLISION_SOLVER_2D_H -#include "shape_2d_sw.h" +#include "godot_shape_2d.h" -class CollisionSolver2DSW { +class GodotCollisionSolver2D { public: typedef void (*CallbackResult)(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata); private: - static bool solve_static_world_margin(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); - static bool concave_callback(void *p_userdata, Shape2DSW *p_convex); - static bool solve_concave(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); - static bool solve_separation_ray(const Shape2DSW *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin = 0); + static bool solve_static_world_boundary(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool concave_callback(void *p_userdata, GodotShape2D *p_convex); + static bool solve_concave(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); + static bool solve_separation_ray(const GodotShape2D *p_shape_A, const Vector2 &p_motion_A, const Transform2D &p_transform_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, Vector2 *r_sep_axis = nullptr, real_t p_margin = 0); public: - static bool solve(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); + static bool solve(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CallbackResult p_result_callback, void *p_userdata, Vector2 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); }; -#endif // COLLISION_SOLVER_2D_SW_H +#endif // GODOT_COLLISION_SOLVER_2D_H diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/godot_collision_solver_2d_sat.cpp index b1aee01bde..63053e8259 100644 --- a/servers/physics_2d/collision_solver_2d_sat.cpp +++ b/servers/physics_2d/godot_collision_solver_2d_sat.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_solver_2d_sat.cpp */ +/* godot_collision_solver_2d_sat.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,17 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "collision_solver_2d_sat.h" +#include "godot_collision_solver_2d_sat.h" #include "core/math/geometry_2d.h" struct _CollectorCallback2D { - CollisionSolver2DSW::CallbackResult callback; - void *userdata; - bool swap; - bool collided; + GodotCollisionSolver2D::CallbackResult callback; + void *userdata = nullptr; + bool swap = false; + bool collided = false; Vector2 normal; - Vector2 *sep_axis; + Vector2 *sep_axis = nullptr; _FORCE_INLINE_ void call(const Vector2 &p_point_A, const Vector2 &p_point_B) { /* @@ -75,9 +75,9 @@ _FORCE_INLINE_ static void _generate_contacts_point_edge(const Vector2 *p_points } struct _generate_contacts_Pair { - bool a; - int idx; - real_t d; + bool a = false; + int idx = 0; + real_t d = 0.0; _FORCE_INLINE_ bool operator<(const _generate_contacts_Pair &l) const { return d < l.d; } }; @@ -146,10 +146,10 @@ static void _generate_contacts_from_supports(const Vector2 *p_points_A, int p_po } }; - int pointcount_B; - int pointcount_A; - const Vector2 *points_A; - const Vector2 *points_B; + int pointcount_B = 0; + int pointcount_A = 0; + const Vector2 *points_A = nullptr; + const Vector2 *points_B = nullptr; if (p_point_count_A > p_point_count_B) { //swap @@ -177,18 +177,20 @@ static void _generate_contacts_from_supports(const Vector2 *p_points_A, int p_po template <class ShapeA, class ShapeB, bool castA = false, bool castB = false, bool withMargin = false> class SeparatorAxisTest2D { - const ShapeA *shape_A; - const ShapeB *shape_B; - const Transform2D *transform_A; - const Transform2D *transform_B; - real_t best_depth; + const ShapeA *shape_A = nullptr; + const ShapeB *shape_B = nullptr; + const Transform2D *transform_A = nullptr; + const Transform2D *transform_B = nullptr; + real_t best_depth = 1e15; Vector2 best_axis; - int best_axis_count; - int best_axis_index; +#ifdef DEBUG_ENABLED + int best_axis_count = 0; + int best_axis_index = -1; +#endif Vector2 motion_A; Vector2 motion_B; - real_t margin_A; - real_t margin_B; + real_t margin_A = 0.0; + real_t margin_B = 0.0; _CollectorCallback2D *callback; public: @@ -364,19 +366,13 @@ public: _FORCE_INLINE_ SeparatorAxisTest2D(const ShapeA *p_shape_A, const Transform2D &p_transform_a, const ShapeB *p_shape_B, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_A = Vector2(), const Vector2 &p_motion_B = Vector2(), real_t p_margin_A = 0, real_t p_margin_B = 0) { margin_A = p_margin_A; margin_B = p_margin_B; - best_depth = 1e15; shape_A = p_shape_A; shape_B = p_shape_B; transform_A = &p_transform_a; transform_B = &p_transform_b; motion_A = p_motion_A; motion_B = p_motion_B; - callback = p_collector; -#ifdef DEBUG_ENABLED - best_axis_count = 0; - best_axis_index = -1; -#endif } }; @@ -388,14 +384,14 @@ public: (castB && !separator.test_axis(((m_a) - ((m_b) + p_motion_b)).normalized())) || \ (castA && castB && !separator.test_axis(((m_a) + p_motion_a - ((m_b) + p_motion_b)).normalized()))) -typedef void (*CollisionFunc)(const Shape2DSW *, const Transform2D &, const Shape2DSW *, const Transform2D &, _CollectorCallback2D *p_collector, const Vector2 &, const Vector2 &, real_t, real_t); +typedef void (*CollisionFunc)(const GodotShape2D *, const Transform2D &, const GodotShape2D *, const Transform2D &, _CollectorCallback2D *p_collector, const Vector2 &, const Vector2 &, real_t, real_t); template <bool castA, bool castB, bool withMargin> -static void _collision_segment_segment(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a); - const SegmentShape2DSW *segment_B = static_cast<const SegmentShape2DSW *>(p_b); +static void _collision_segment_segment(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a); + const GodotSegmentShape2D *segment_B = static_cast<const GodotSegmentShape2D *>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW, SegmentShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, segment_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotSegmentShape2D, GodotSegmentShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, segment_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -434,11 +430,11 @@ static void _collision_segment_segment(const Shape2DSW *p_a, const Transform2D & } template <bool castA, bool castB, bool withMargin> -static void _collision_segment_circle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a); - const CircleShape2DSW *circle_B = static_cast<const CircleShape2DSW *>(p_b); +static void _collision_segment_circle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a); + const GodotCircleShape2D *circle_B = static_cast<const GodotCircleShape2D *>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW, CircleShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, circle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotSegmentShape2D, GodotCircleShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, circle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -467,11 +463,11 @@ static void _collision_segment_circle(const Shape2DSW *p_a, const Transform2D &p } template <bool castA, bool castB, bool withMargin> -static void _collision_segment_rectangle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a); - const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW *>(p_b); +static void _collision_segment_rectangle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a); + const GodotRectangleShape2D *rectangle_B = static_cast<const GodotRectangleShape2D *>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW, RectangleShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotSegmentShape2D, GodotRectangleShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -538,11 +534,11 @@ static void _collision_segment_rectangle(const Shape2DSW *p_a, const Transform2D } template <bool castA, bool castB, bool withMargin> -static void _collision_segment_capsule(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a); - const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW *>(p_b); +static void _collision_segment_capsule(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a); + const GodotCapsuleShape2D *capsule_B = static_cast<const GodotCapsuleShape2D *>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW, CapsuleShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotSegmentShape2D, GodotCapsuleShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -579,11 +575,11 @@ static void _collision_segment_capsule(const Shape2DSW *p_a, const Transform2D & } template <bool castA, bool castB, bool withMargin> -static void _collision_segment_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const SegmentShape2DSW *segment_A = static_cast<const SegmentShape2DSW *>(p_a); - const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b); +static void _collision_segment_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotSegmentShape2D *segment_A = static_cast<const GodotSegmentShape2D *>(p_a); + const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b); - SeparatorAxisTest2D<SegmentShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(segment_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotSegmentShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(segment_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -618,11 +614,11 @@ static void _collision_segment_convex_polygon(const Shape2DSW *p_a, const Transf ///////// template <bool castA, bool castB, bool withMargin> -static void _collision_circle_circle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW *>(p_a); - const CircleShape2DSW *circle_B = static_cast<const CircleShape2DSW *>(p_b); +static void _collision_circle_circle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotCircleShape2D *circle_A = static_cast<const GodotCircleShape2D *>(p_a); + const GodotCircleShape2D *circle_B = static_cast<const GodotCircleShape2D *>(p_b); - SeparatorAxisTest2D<CircleShape2DSW, CircleShape2DSW, castA, castB, withMargin> separator(circle_A, p_transform_a, circle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotCircleShape2D, GodotCircleShape2D, castA, castB, withMargin> separator(circle_A, p_transform_a, circle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -640,11 +636,11 @@ static void _collision_circle_circle(const Shape2DSW *p_a, const Transform2D &p_ } template <bool castA, bool castB, bool withMargin> -static void _collision_circle_rectangle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW *>(p_a); - const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW *>(p_b); +static void _collision_circle_rectangle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotCircleShape2D *circle_A = static_cast<const GodotCircleShape2D *>(p_a); + const GodotRectangleShape2D *rectangle_B = static_cast<const GodotRectangleShape2D *>(p_b); - SeparatorAxisTest2D<CircleShape2DSW, RectangleShape2DSW, castA, castB, withMargin> separator(circle_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotCircleShape2D, GodotRectangleShape2D, castA, castB, withMargin> separator(circle_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -698,11 +694,11 @@ static void _collision_circle_rectangle(const Shape2DSW *p_a, const Transform2D } template <bool castA, bool castB, bool withMargin> -static void _collision_circle_capsule(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW *>(p_a); - const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW *>(p_b); +static void _collision_circle_capsule(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotCircleShape2D *circle_A = static_cast<const GodotCircleShape2D *>(p_a); + const GodotCapsuleShape2D *capsule_B = static_cast<const GodotCapsuleShape2D *>(p_b); - SeparatorAxisTest2D<CircleShape2DSW, CapsuleShape2DSW, castA, castB, withMargin> separator(circle_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotCircleShape2D, GodotCapsuleShape2D, castA, castB, withMargin> separator(circle_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -731,11 +727,11 @@ static void _collision_circle_capsule(const Shape2DSW *p_a, const Transform2D &p } template <bool castA, bool castB, bool withMargin> -static void _collision_circle_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const CircleShape2DSW *circle_A = static_cast<const CircleShape2DSW *>(p_a); - const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b); +static void _collision_circle_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotCircleShape2D *circle_A = static_cast<const GodotCircleShape2D *>(p_a); + const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b); - SeparatorAxisTest2D<CircleShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(circle_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotCircleShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(circle_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -762,11 +758,11 @@ static void _collision_circle_convex_polygon(const Shape2DSW *p_a, const Transfo ///////// template <bool castA, bool castB, bool withMargin> -static void _collision_rectangle_rectangle(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW *>(p_a); - const RectangleShape2DSW *rectangle_B = static_cast<const RectangleShape2DSW *>(p_b); +static void _collision_rectangle_rectangle(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotRectangleShape2D *rectangle_A = static_cast<const GodotRectangleShape2D *>(p_a); + const GodotRectangleShape2D *rectangle_B = static_cast<const GodotRectangleShape2D *>(p_b); - SeparatorAxisTest2D<RectangleShape2DSW, RectangleShape2DSW, castA, castB, withMargin> separator(rectangle_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotRectangleShape2D, GodotRectangleShape2D, castA, castB, withMargin> separator(rectangle_A, p_transform_a, rectangle_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -836,11 +832,11 @@ static void _collision_rectangle_rectangle(const Shape2DSW *p_a, const Transform } template <bool castA, bool castB, bool withMargin> -static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW *>(p_a); - const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW *>(p_b); +static void _collision_rectangle_capsule(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotRectangleShape2D *rectangle_A = static_cast<const GodotRectangleShape2D *>(p_a); + const GodotCapsuleShape2D *capsule_B = static_cast<const GodotCapsuleShape2D *>(p_b); - SeparatorAxisTest2D<RectangleShape2DSW, CapsuleShape2DSW, castA, castB, withMargin> separator(rectangle_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotRectangleShape2D, GodotCapsuleShape2D, castA, castB, withMargin> separator(rectangle_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -914,11 +910,11 @@ static void _collision_rectangle_capsule(const Shape2DSW *p_a, const Transform2D } template <bool castA, bool castB, bool withMargin> -static void _collision_rectangle_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const RectangleShape2DSW *rectangle_A = static_cast<const RectangleShape2DSW *>(p_a); - const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b); +static void _collision_rectangle_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotRectangleShape2D *rectangle_A = static_cast<const GodotRectangleShape2D *>(p_a); + const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b); - SeparatorAxisTest2D<RectangleShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(rectangle_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotRectangleShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(rectangle_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -976,11 +972,11 @@ static void _collision_rectangle_convex_polygon(const Shape2DSW *p_a, const Tran ///////// template <bool castA, bool castB, bool withMargin> -static void _collision_capsule_capsule(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const CapsuleShape2DSW *capsule_A = static_cast<const CapsuleShape2DSW *>(p_a); - const CapsuleShape2DSW *capsule_B = static_cast<const CapsuleShape2DSW *>(p_b); +static void _collision_capsule_capsule(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotCapsuleShape2D *capsule_A = static_cast<const GodotCapsuleShape2D *>(p_a); + const GodotCapsuleShape2D *capsule_B = static_cast<const GodotCapsuleShape2D *>(p_b); - SeparatorAxisTest2D<CapsuleShape2DSW, CapsuleShape2DSW, castA, castB, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotCapsuleShape2D, GodotCapsuleShape2D, castA, castB, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -1024,11 +1020,11 @@ static void _collision_capsule_capsule(const Shape2DSW *p_a, const Transform2D & } template <bool castA, bool castB, bool withMargin> -static void _collision_capsule_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const CapsuleShape2DSW *capsule_A = static_cast<const CapsuleShape2DSW *>(p_a); - const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b); +static void _collision_capsule_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotCapsuleShape2D *capsule_A = static_cast<const GodotCapsuleShape2D *>(p_a); + const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b); - SeparatorAxisTest2D<CapsuleShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(capsule_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotCapsuleShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(capsule_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -1070,11 +1066,11 @@ static void _collision_capsule_convex_polygon(const Shape2DSW *p_a, const Transf ///////// template <bool castA, bool castB, bool withMargin> -static void _collision_convex_polygon_convex_polygon(const Shape2DSW *p_a, const Transform2D &p_transform_a, const Shape2DSW *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { - const ConvexPolygonShape2DSW *convex_A = static_cast<const ConvexPolygonShape2DSW *>(p_a); - const ConvexPolygonShape2DSW *convex_B = static_cast<const ConvexPolygonShape2DSW *>(p_b); +static void _collision_convex_polygon_convex_polygon(const GodotShape2D *p_a, const Transform2D &p_transform_a, const GodotShape2D *p_b, const Transform2D &p_transform_b, _CollectorCallback2D *p_collector, const Vector2 &p_motion_a, const Vector2 &p_motion_b, real_t p_margin_A, real_t p_margin_B) { + const GodotConvexPolygonShape2D *convex_A = static_cast<const GodotConvexPolygonShape2D *>(p_a); + const GodotConvexPolygonShape2D *convex_B = static_cast<const GodotConvexPolygonShape2D *>(p_b); - SeparatorAxisTest2D<ConvexPolygonShape2DSW, ConvexPolygonShape2DSW, castA, castB, withMargin> separator(convex_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); + SeparatorAxisTest2D<GodotConvexPolygonShape2D, GodotConvexPolygonShape2D, castA, castB, withMargin> separator(convex_A, p_transform_a, convex_B, p_transform_b, p_collector, p_motion_a, p_motion_b, p_margin_A, p_margin_B); if (!separator.test_previous_axis()) { return; @@ -1111,16 +1107,16 @@ static void _collision_convex_polygon_convex_polygon(const Shape2DSW *p_a, const //////// -bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) { +bool sat_2d_calculate_penetration(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, GodotCollisionSolver2D::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector2 *sep_axis, real_t p_margin_A, real_t p_margin_B) { PhysicsServer2D::ShapeType type_A = p_shape_A->get_type(); - ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_WORLD_MARGIN, false); + ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_WORLD_BOUNDARY, false); ERR_FAIL_COND_V(type_A == PhysicsServer2D::SHAPE_SEPARATION_RAY, false); ERR_FAIL_COND_V(p_shape_A->is_concave(), false); PhysicsServer2D::ShapeType type_B = p_shape_B->get_type(); - ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_WORLD_MARGIN, false); + ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_WORLD_BOUNDARY, false); ERR_FAIL_COND_V(type_B == PhysicsServer2D::SHAPE_SEPARATION_RAY, false); ERR_FAIL_COND_V(p_shape_B->is_concave(), false); @@ -1363,8 +1359,8 @@ bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D callback.collided = false; callback.sep_axis = sep_axis; - const Shape2DSW *A = p_shape_A; - const Shape2DSW *B = p_shape_B; + const GodotShape2D *A = p_shape_A; + const GodotShape2D *B = p_shape_B; const Transform2D *transform_A = &p_transform_A; const Transform2D *transform_B = &p_transform_B; const Vector2 *motion_A = &p_motion_A; diff --git a/servers/physics_2d/collision_solver_2d_sat.h b/servers/physics_2d/godot_collision_solver_2d_sat.h index 49cc5176f9..1517b90a19 100644 --- a/servers/physics_2d/collision_solver_2d_sat.h +++ b/servers/physics_2d/godot_collision_solver_2d_sat.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_solver_2d_sat.h */ +/* godot_collision_solver_2d_sat.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef COLLISION_SOLVER_2D_SAT_H -#define COLLISION_SOLVER_2D_SAT_H +#ifndef GODOT_COLLISION_SOLVER_2D_SAT_H +#define GODOT_COLLISION_SOLVER_2D_SAT_H -#include "collision_solver_2d_sw.h" +#include "godot_collision_solver_2d.h" -bool sat_2d_calculate_penetration(const Shape2DSW *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const Shape2DSW *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, CollisionSolver2DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); +bool sat_2d_calculate_penetration(const GodotShape2D *p_shape_A, const Transform2D &p_transform_A, const Vector2 &p_motion_A, const GodotShape2D *p_shape_B, const Transform2D &p_transform_B, const Vector2 &p_motion_B, GodotCollisionSolver2D::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector2 *sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); -#endif // COLLISION_SOLVER_2D_SAT_H +#endif // GODOT_COLLISION_SOLVER_2D_SAT_H diff --git a/servers/physics_2d/constraint_2d_sw.h b/servers/physics_2d/godot_constraint_2d.h index 5e8dfbe570..84f975e583 100644 --- a/servers/physics_2d/constraint_2d_sw.h +++ b/servers/physics_2d/godot_constraint_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* constraint_2d_sw.h */ +/* godot_constraint_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,25 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CONSTRAINT_2D_SW_H -#define CONSTRAINT_2D_SW_H +#ifndef GODOT_CONSTRAINT_2D_H +#define GODOT_CONSTRAINT_2D_H -#include "body_2d_sw.h" +#include "godot_body_2d.h" -class Constraint2DSW { - Body2DSW **_body_ptr; +class GodotConstraint2D { + GodotBody2D **_body_ptr; int _body_count; - uint64_t island_step; - bool disabled_collisions_between_bodies; + uint64_t island_step = 0; + bool disabled_collisions_between_bodies = true; RID self; protected: - Constraint2DSW(Body2DSW **p_body_ptr = nullptr, int p_body_count = 0) { + GodotConstraint2D(GodotBody2D **p_body_ptr = nullptr, int p_body_count = 0) { _body_ptr = p_body_ptr; _body_count = p_body_count; - island_step = 0; - disabled_collisions_between_bodies = true; } public: @@ -56,7 +54,7 @@ public: _FORCE_INLINE_ uint64_t get_island_step() const { return island_step; } _FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; } - _FORCE_INLINE_ Body2DSW **get_body_ptr() const { return _body_ptr; } + _FORCE_INLINE_ GodotBody2D **get_body_ptr() const { return _body_ptr; } _FORCE_INLINE_ int get_body_count() const { return _body_count; } _FORCE_INLINE_ void disable_collisions_between_bodies(const bool p_disabled) { disabled_collisions_between_bodies = p_disabled; } @@ -66,7 +64,7 @@ public: virtual bool pre_solve(real_t p_step) = 0; virtual void solve(real_t p_step) = 0; - virtual ~Constraint2DSW() {} + virtual ~GodotConstraint2D() {} }; -#endif // CONSTRAINT_2D_SW_H +#endif // GODOT_CONSTRAINT_2D_H diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/godot_joints_2d.cpp index 5a0a628fbc..7c08c2f4b4 100644 --- a/servers/physics_2d/joints_2d_sw.cpp +++ b/servers/physics_2d/godot_joints_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joints_2d_sw.cpp */ +/* godot_joints_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "joints_2d_sw.h" +#include "godot_joints_2d.h" -#include "space_2d_sw.h" +#include "godot_space_2d.h" //based on chipmunk joint constraints @@ -55,7 +55,7 @@ * SOFTWARE. */ -void Joint2DSW::copy_settings_from(Joint2DSW *p_joint) { +void GodotJoint2D::copy_settings_from(GodotJoint2D *p_joint) { set_self(p_joint->get_self()); set_max_force(p_joint->get_max_force()); set_bias(p_joint->get_bias()); @@ -63,18 +63,18 @@ void Joint2DSW::copy_settings_from(Joint2DSW *p_joint) { disable_collisions_between_bodies(p_joint->is_disabled_collisions_between_bodies()); } -static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const Vector2 &rB, const Vector2 &n) { - real_t value = 0; +static inline real_t k_scalar(GodotBody2D *a, GodotBody2D *b, const Vector2 &rA, const Vector2 &rB, const Vector2 &n) { + real_t value = 0.0; { value += a->get_inv_mass(); - real_t rcn = rA.cross(n); + real_t rcn = (rA - a->get_center_of_mass()).cross(n); value += a->get_inv_inertia() * rcn * rcn; } if (b) { value += b->get_inv_mass(); - real_t rcn = rB.cross(n); + real_t rcn = (rB - b->get_center_of_mass()).cross(n); value += b->get_inv_inertia() * rcn * rcn; } @@ -82,21 +82,21 @@ static inline real_t k_scalar(Body2DSW *a, Body2DSW *b, const Vector2 &rA, const } static inline Vector2 -relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB) { - Vector2 sum = a->get_linear_velocity() - rA.orthogonal() * a->get_angular_velocity(); +relative_velocity(GodotBody2D *a, GodotBody2D *b, Vector2 rA, Vector2 rB) { + Vector2 sum = a->get_linear_velocity() - (rA - a->get_center_of_mass()).orthogonal() * a->get_angular_velocity(); if (b) { - return (b->get_linear_velocity() - rB.orthogonal() * b->get_angular_velocity()) - sum; + return (b->get_linear_velocity() - (rB - b->get_center_of_mass()).orthogonal() * b->get_angular_velocity()) - sum; } else { return -sum; } } static inline real_t -normal_relative_velocity(Body2DSW *a, Body2DSW *b, Vector2 rA, Vector2 rB, Vector2 n) { +normal_relative_velocity(GodotBody2D *a, GodotBody2D *b, Vector2 rA, Vector2 rB, Vector2 n) { return relative_velocity(a, b, rA, rB).dot(n); } -bool PinJoint2DSW::setup(real_t p_step) { +bool GodotPinJoint2D::setup(real_t p_step) { dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); @@ -104,7 +104,7 @@ bool PinJoint2DSW::setup(real_t p_step) { return false; } - Space2DSW *space = A->get_space(); + GodotSpace2D *space = A->get_space(); ERR_FAIL_COND_V(!space, false); rA = A->get_transform().basis_xform(anchor_A); @@ -158,7 +158,7 @@ inline Vector2 custom_cross(const Vector2 &p_vec, real_t p_other) { return Vector2(p_other * p_vec.y, -p_other * p_vec.x); } -bool PinJoint2DSW::pre_solve(real_t p_step) { +bool GodotPinJoint2D::pre_solve(real_t p_step) { // Apply accumulated impulse. if (dynamic_A) { A->apply_impulse(-P, rA); @@ -170,13 +170,13 @@ bool PinJoint2DSW::pre_solve(real_t p_step) { return true; } -void PinJoint2DSW::solve(real_t p_step) { +void GodotPinJoint2D::solve(real_t p_step) { // compute relative velocity - Vector2 vA = A->get_linear_velocity() - custom_cross(rA, A->get_angular_velocity()); + Vector2 vA = A->get_linear_velocity() - custom_cross(rA - A->get_center_of_mass(), A->get_angular_velocity()); Vector2 rel_vel; if (B) { - rel_vel = B->get_linear_velocity() - custom_cross(rB, B->get_angular_velocity()) - vA; + rel_vel = B->get_linear_velocity() - custom_cross(rB - B->get_center_of_mass(), B->get_angular_velocity()) - vA; } else { rel_vel = -vA; } @@ -193,28 +193,26 @@ void PinJoint2DSW::solve(real_t p_step) { P += impulse; } -void PinJoint2DSW::set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value) { +void GodotPinJoint2D::set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value) { if (p_param == PhysicsServer2D::PIN_JOINT_SOFTNESS) { softness = p_value; } } -real_t PinJoint2DSW::get_param(PhysicsServer2D::PinJointParam p_param) const { +real_t GodotPinJoint2D::get_param(PhysicsServer2D::PinJointParam p_param) const { if (p_param == PhysicsServer2D::PIN_JOINT_SOFTNESS) { return softness; } ERR_FAIL_V(0); } -PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b) : - Joint2DSW(_arr, p_body_b ? 2 : 1) { +GodotPinJoint2D::GodotPinJoint2D(const Vector2 &p_pos, GodotBody2D *p_body_a, GodotBody2D *p_body_b) : + GodotJoint2D(_arr, p_body_b ? 2 : 1) { A = p_body_a; B = p_body_b; anchor_A = p_body_a->get_inv_transform().xform(p_pos); anchor_B = p_body_b ? p_body_b->get_inv_transform().xform(p_pos) : p_pos; - softness = 0; - p_body_a->add_constraint(this, 0); if (p_body_b) { p_body_b->add_constraint(this, 1); @@ -226,7 +224,7 @@ PinJoint2DSW::PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p ////////////////////////////////////////////// static inline void -k_tensor(Body2DSW *a, Body2DSW *b, Vector2 r1, Vector2 r2, Vector2 *k1, Vector2 *k2) { +k_tensor(GodotBody2D *a, GodotBody2D *b, Vector2 r1, Vector2 r2, Vector2 *k1, Vector2 *k2) { // calculate mass matrix // If I wasn't lazy and wrote a proper matrix class, this wouldn't be so gross... real_t k11, k12, k21, k22; @@ -238,6 +236,9 @@ k_tensor(Body2DSW *a, Body2DSW *b, Vector2 r1, Vector2 r2, Vector2 *k1, Vector2 k21 = 0.0f; k22 = m_sum; + r1 -= a->get_center_of_mass(); + r2 -= b->get_center_of_mass(); + // add the influence from r1 real_t a_i_inv = a->get_inv_inertia(); real_t r1xsq = r1.x * r1.x * a_i_inv; @@ -272,7 +273,7 @@ mult_k(const Vector2 &vr, const Vector2 &k1, const Vector2 &k2) { return Vector2(vr.dot(k1), vr.dot(k2)); } -bool GrooveJoint2DSW::setup(real_t p_step) { +bool GodotGrooveJoint2D::setup(real_t p_step) { dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); @@ -280,7 +281,7 @@ bool GrooveJoint2DSW::setup(real_t p_step) { return false; } - Space2DSW *space = A->get_space(); + GodotSpace2D *space = A->get_space(); ERR_FAIL_COND_V(!space, false); // calculate endpoints in worldspace @@ -328,7 +329,7 @@ bool GrooveJoint2DSW::setup(real_t p_step) { return true; } -bool GrooveJoint2DSW::pre_solve(real_t p_step) { +bool GodotGrooveJoint2D::pre_solve(real_t p_step) { // Apply accumulated impulse. if (dynamic_A) { A->apply_impulse(-jn_acc, rA); @@ -340,7 +341,7 @@ bool GrooveJoint2DSW::pre_solve(real_t p_step) { return true; } -void GrooveJoint2DSW::solve(real_t p_step) { +void GodotGrooveJoint2D::solve(real_t p_step) { // compute impulse Vector2 vr = relative_velocity(A, B, rA, rB); @@ -360,8 +361,8 @@ void GrooveJoint2DSW::solve(real_t p_step) { } } -GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b) : - Joint2DSW(_arr, 2) { +GodotGrooveJoint2D::GodotGrooveJoint2D(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, GodotBody2D *p_body_a, GodotBody2D *p_body_b) : + GodotJoint2D(_arr, 2) { A = p_body_a; B = p_body_b; @@ -378,7 +379,7 @@ GrooveJoint2DSW::GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_ ////////////////////////////////////////////// ////////////////////////////////////////////// -bool DampedSpringJoint2DSW::setup(real_t p_step) { +bool GodotDampedSpringJoint2D::setup(real_t p_step) { dynamic_A = (A->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); dynamic_B = (B->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC); @@ -411,7 +412,7 @@ bool DampedSpringJoint2DSW::setup(real_t p_step) { return true; } -bool DampedSpringJoint2DSW::pre_solve(real_t p_step) { +bool GodotDampedSpringJoint2D::pre_solve(real_t p_step) { // Apply spring force. if (dynamic_A) { A->apply_impulse(-j, rA); @@ -423,7 +424,7 @@ bool DampedSpringJoint2DSW::pre_solve(real_t p_step) { return true; } -void DampedSpringJoint2DSW::solve(real_t p_step) { +void GodotDampedSpringJoint2D::solve(real_t p_step) { // compute relative velocity real_t vrn = normal_relative_velocity(A, B, rA, rB, n) - target_vrn; @@ -441,7 +442,7 @@ void DampedSpringJoint2DSW::solve(real_t p_step) { } } -void DampedSpringJoint2DSW::set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value) { +void GodotDampedSpringJoint2D::set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value) { switch (p_param) { case PhysicsServer2D::DAMPED_SPRING_REST_LENGTH: { rest_length = p_value; @@ -455,7 +456,7 @@ void DampedSpringJoint2DSW::set_param(PhysicsServer2D::DampedSpringParam p_param } } -real_t DampedSpringJoint2DSW::get_param(PhysicsServer2D::DampedSpringParam p_param) const { +real_t GodotDampedSpringJoint2D::get_param(PhysicsServer2D::DampedSpringParam p_param) const { switch (p_param) { case PhysicsServer2D::DAMPED_SPRING_REST_LENGTH: { return rest_length; @@ -471,16 +472,14 @@ real_t DampedSpringJoint2DSW::get_param(PhysicsServer2D::DampedSpringParam p_par ERR_FAIL_V(0); } -DampedSpringJoint2DSW::DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, Body2DSW *p_body_a, Body2DSW *p_body_b) : - Joint2DSW(_arr, 2) { +GodotDampedSpringJoint2D::GodotDampedSpringJoint2D(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, GodotBody2D *p_body_a, GodotBody2D *p_body_b) : + GodotJoint2D(_arr, 2) { A = p_body_a; B = p_body_b; anchor_A = A->get_inv_transform().xform(p_anchor_a); anchor_B = B->get_inv_transform().xform(p_anchor_b); rest_length = p_anchor_a.distance_to(p_anchor_b); - stiffness = 20; - damping = 1.5; A->add_constraint(this, 0); B->add_constraint(this, 1); diff --git a/servers/physics_2d/joints_2d_sw.h b/servers/physics_2d/godot_joints_2d.h index ccc5c585a0..4c97190d01 100644 --- a/servers/physics_2d/joints_2d_sw.h +++ b/servers/physics_2d/godot_joints_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joints_2d_sw.h */ +/* godot_joints_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,16 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JOINTS_2D_SW_H -#define JOINTS_2D_SW_H +#ifndef GODOT_JOINTS_2D_H +#define GODOT_JOINTS_2D_H -#include "body_2d_sw.h" -#include "constraint_2d_sw.h" +#include "godot_body_2d.h" +#include "godot_constraint_2d.h" -class Joint2DSW : public Constraint2DSW { - real_t max_force; - real_t bias; - real_t max_bias; +class GodotJoint2D : public GodotConstraint2D { + real_t bias = 0; + real_t max_bias = 3.40282e+38; + real_t max_force = 3.40282e+38; protected: bool dynamic_A = false; @@ -57,18 +57,15 @@ public: virtual bool pre_solve(real_t p_step) override { return false; } virtual void solve(real_t p_step) override {} - void copy_settings_from(Joint2DSW *p_joint); + void copy_settings_from(GodotJoint2D *p_joint); virtual PhysicsServer2D::JointType get_type() const { return PhysicsServer2D::JOINT_TYPE_MAX; } - Joint2DSW(Body2DSW **p_body_ptr = nullptr, int p_body_count = 0) : - Constraint2DSW(p_body_ptr, p_body_count) { - bias = 0; - max_force = max_bias = 3.40282e+38; - }; + GodotJoint2D(GodotBody2D **p_body_ptr = nullptr, int p_body_count = 0) : + GodotConstraint2D(p_body_ptr, p_body_count) {} - virtual ~Joint2DSW() { + virtual ~GodotJoint2D() { for (int i = 0; i < get_body_count(); i++) { - Body2DSW *body = get_body_ptr()[i]; + GodotBody2D *body = get_body_ptr()[i]; if (body) { body->remove_constraint(this, i); } @@ -76,14 +73,14 @@ public: }; }; -class PinJoint2DSW : public Joint2DSW { +class GodotPinJoint2D : public GodotJoint2D { union { struct { - Body2DSW *A; - Body2DSW *B; + GodotBody2D *A; + GodotBody2D *B; }; - Body2DSW *_arr[2]; + GodotBody2D *_arr[2] = { nullptr, nullptr }; }; Transform2D M; @@ -92,7 +89,7 @@ class PinJoint2DSW : public Joint2DSW { Vector2 anchor_B; Vector2 bias; Vector2 P; - real_t softness; + real_t softness = 0.0; public: virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_PIN; } @@ -104,17 +101,17 @@ public: void set_param(PhysicsServer2D::PinJointParam p_param, real_t p_value); real_t get_param(PhysicsServer2D::PinJointParam p_param) const; - PinJoint2DSW(const Vector2 &p_pos, Body2DSW *p_body_a, Body2DSW *p_body_b = nullptr); + GodotPinJoint2D(const Vector2 &p_pos, GodotBody2D *p_body_a, GodotBody2D *p_body_b = nullptr); }; -class GrooveJoint2DSW : public Joint2DSW { +class GodotGrooveJoint2D : public GodotJoint2D { union { struct { - Body2DSW *A; - Body2DSW *B; + GodotBody2D *A; + GodotBody2D *B; }; - Body2DSW *_arr[2]; + GodotBody2D *_arr[2] = { nullptr, nullptr }; }; Vector2 A_groove_1; @@ -123,13 +120,13 @@ class GrooveJoint2DSW : public Joint2DSW { Vector2 B_anchor; Vector2 jn_acc; Vector2 gbias; - real_t jn_max; - real_t clamp; + real_t jn_max = 0.0; + real_t clamp = 0.0; Vector2 xf_normal; Vector2 rA, rB; Vector2 k1, k2; - bool correct; + bool correct = false; public: virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_GROOVE; } @@ -138,32 +135,32 @@ public: virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - GrooveJoint2DSW(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, Body2DSW *p_body_a, Body2DSW *p_body_b); + GodotGrooveJoint2D(const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, GodotBody2D *p_body_a, GodotBody2D *p_body_b); }; -class DampedSpringJoint2DSW : public Joint2DSW { +class GodotDampedSpringJoint2D : public GodotJoint2D { union { struct { - Body2DSW *A; - Body2DSW *B; + GodotBody2D *A; + GodotBody2D *B; }; - Body2DSW *_arr[2]; + GodotBody2D *_arr[2] = { nullptr, nullptr }; }; Vector2 anchor_A; Vector2 anchor_B; - real_t rest_length; - real_t damping; - real_t stiffness; + real_t rest_length = 0.0; + real_t damping = 1.5; + real_t stiffness = 20.0; Vector2 rA, rB; Vector2 n; Vector2 j; - real_t n_mass; - real_t target_vrn; - real_t v_coef; + real_t n_mass = 0.0; + real_t target_vrn = 0.0; + real_t v_coef = 0.0; public: virtual PhysicsServer2D::JointType get_type() const override { return PhysicsServer2D::JOINT_TYPE_DAMPED_SPRING; } @@ -175,7 +172,7 @@ public: void set_param(PhysicsServer2D::DampedSpringParam p_param, real_t p_value); real_t get_param(PhysicsServer2D::DampedSpringParam p_param) const; - DampedSpringJoint2DSW(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, Body2DSW *p_body_a, Body2DSW *p_body_b); + GodotDampedSpringJoint2D(const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, GodotBody2D *p_body_a, GodotBody2D *p_body_b); }; -#endif // JOINTS_2D_SW_H +#endif // GODOT_JOINTS_2D_H diff --git a/servers/physics_2d/godot_physics_server_2d.cpp b/servers/physics_2d/godot_physics_server_2d.cpp new file mode 100644 index 0000000000..8ac27077fc --- /dev/null +++ b/servers/physics_2d/godot_physics_server_2d.cpp @@ -0,0 +1,1343 @@ +/*************************************************************************/ +/* godot_physics_server_2d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "godot_physics_server_2d.h" + +#include "godot_body_direct_state_2d.h" +#include "godot_broad_phase_2d_bvh.h" +#include "godot_collision_solver_2d.h" + +#include "core/config/project_settings.h" +#include "core/debugger/engine_debugger.h" +#include "core/os/os.h" + +#define FLUSH_QUERY_CHECK(m_object) \ + ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead."); + +RID GodotPhysicsServer2D::_shape_create(ShapeType p_shape) { + GodotShape2D *shape = nullptr; + switch (p_shape) { + case SHAPE_WORLD_BOUNDARY: { + shape = memnew(GodotWorldBoundaryShape2D); + } break; + case SHAPE_SEPARATION_RAY: { + shape = memnew(GodotSeparationRayShape2D); + } break; + case SHAPE_SEGMENT: { + shape = memnew(GodotSegmentShape2D); + } break; + case SHAPE_CIRCLE: { + shape = memnew(GodotCircleShape2D); + } break; + case SHAPE_RECTANGLE: { + shape = memnew(GodotRectangleShape2D); + } break; + case SHAPE_CAPSULE: { + shape = memnew(GodotCapsuleShape2D); + } break; + case SHAPE_CONVEX_POLYGON: { + shape = memnew(GodotConvexPolygonShape2D); + } break; + case SHAPE_CONCAVE_POLYGON: { + shape = memnew(GodotConcavePolygonShape2D); + } break; + case SHAPE_CUSTOM: { + ERR_FAIL_V(RID()); + + } break; + } + + RID id = shape_owner.make_rid(shape); + shape->set_self(id); + + return id; +} + +RID GodotPhysicsServer2D::world_boundary_shape_create() { + return _shape_create(SHAPE_WORLD_BOUNDARY); +} + +RID GodotPhysicsServer2D::separation_ray_shape_create() { + return _shape_create(SHAPE_SEPARATION_RAY); +} + +RID GodotPhysicsServer2D::segment_shape_create() { + return _shape_create(SHAPE_SEGMENT); +} + +RID GodotPhysicsServer2D::circle_shape_create() { + return _shape_create(SHAPE_CIRCLE); +} + +RID GodotPhysicsServer2D::rectangle_shape_create() { + return _shape_create(SHAPE_RECTANGLE); +} + +RID GodotPhysicsServer2D::capsule_shape_create() { + return _shape_create(SHAPE_CAPSULE); +} + +RID GodotPhysicsServer2D::convex_polygon_shape_create() { + return _shape_create(SHAPE_CONVEX_POLYGON); +} + +RID GodotPhysicsServer2D::concave_polygon_shape_create() { + return _shape_create(SHAPE_CONCAVE_POLYGON); +} + +void GodotPhysicsServer2D::shape_set_data(RID p_shape, const Variant &p_data) { + GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + shape->set_data(p_data); +}; + +void GodotPhysicsServer2D::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) { + GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + shape->set_custom_bias(p_bias); +} + +PhysicsServer2D::ShapeType GodotPhysicsServer2D::shape_get_type(RID p_shape) const { + const GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM); + return shape->get_type(); +}; + +Variant GodotPhysicsServer2D::shape_get_data(RID p_shape) const { + const GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND_V(!shape, Variant()); + ERR_FAIL_COND_V(!shape->is_configured(), Variant()); + return shape->get_data(); +}; + +real_t GodotPhysicsServer2D::shape_get_custom_solver_bias(RID p_shape) const { + const GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND_V(!shape, 0); + return shape->get_custom_bias(); +} + +void GodotPhysicsServer2D::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) { + CollCbkData *cbk = (CollCbkData *)p_userdata; + + if (cbk->max == 0) { + return; + } + + Vector2 rel_dir = (p_point_A - p_point_B); + real_t rel_length2 = rel_dir.length_squared(); + if (cbk->valid_dir != Vector2()) { + if (cbk->valid_depth < 10e20) { + if (rel_length2 > cbk->valid_depth * cbk->valid_depth || + (rel_length2 > CMP_EPSILON && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON)) { + cbk->invalid_by_dir++; + return; + } + } else { + if (rel_length2 > 0 && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON) { + return; + } + } + } + + if (cbk->amount == cbk->max) { + //find least deep + real_t min_depth = 1e20; + int min_depth_idx = 0; + for (int i = 0; i < cbk->amount; i++) { + real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]); + if (d < min_depth) { + min_depth = d; + min_depth_idx = i; + } + } + + if (rel_length2 < min_depth) { + return; + } + cbk->ptr[min_depth_idx * 2 + 0] = p_point_A; + cbk->ptr[min_depth_idx * 2 + 1] = p_point_B; + cbk->passed++; + + } else { + cbk->ptr[cbk->amount * 2 + 0] = p_point_A; + cbk->ptr[cbk->amount * 2 + 1] = p_point_B; + cbk->amount++; + cbk->passed++; + } +} + +bool GodotPhysicsServer2D::shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) { + GodotShape2D *shape_A = shape_owner.get_or_null(p_shape_A); + ERR_FAIL_COND_V(!shape_A, false); + GodotShape2D *shape_B = shape_owner.get_or_null(p_shape_B); + ERR_FAIL_COND_V(!shape_B, false); + + if (p_result_max == 0) { + return GodotCollisionSolver2D::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, nullptr, nullptr); + } + + CollCbkData cbk; + cbk.max = p_result_max; + cbk.amount = 0; + cbk.passed = 0; + cbk.ptr = r_results; + + bool res = GodotCollisionSolver2D::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, _shape_col_cbk, &cbk); + r_result_count = cbk.amount; + return res; +} + +RID GodotPhysicsServer2D::space_create() { + GodotSpace2D *space = memnew(GodotSpace2D); + RID id = space_owner.make_rid(space); + space->set_self(id); + RID area_id = area_create(); + GodotArea2D *area = area_owner.get_or_null(area_id); + ERR_FAIL_COND_V(!area, RID()); + space->set_default_area(area); + area->set_space(space); + area->set_priority(-1); + + return id; +}; + +void GodotPhysicsServer2D::space_set_active(RID p_space, bool p_active) { + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + if (p_active) { + active_spaces.insert(space); + } else { + active_spaces.erase(space); + } +} + +bool GodotPhysicsServer2D::space_is_active(RID p_space) const { + const GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, false); + + return active_spaces.has(space); +} + +void GodotPhysicsServer2D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + + space->set_param(p_param, p_value); +} + +real_t GodotPhysicsServer2D::space_get_param(RID p_space, SpaceParameter p_param) const { + const GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, 0); + return space->get_param(p_param); +} + +void GodotPhysicsServer2D::space_set_debug_contacts(RID p_space, int p_max_contacts) { + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + space->set_debug_contacts(p_max_contacts); +} + +Vector<Vector2> GodotPhysicsServer2D::space_get_contacts(RID p_space) const { + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, Vector<Vector2>()); + return space->get_debug_contacts(); +} + +int GodotPhysicsServer2D::space_get_contact_count(RID p_space) const { + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, 0); + return space->get_debug_contact_count(); +} + +PhysicsDirectSpaceState2D *GodotPhysicsServer2D::space_get_direct_state(RID p_space) { + GodotSpace2D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, nullptr); + ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification."); + + return space->get_direct_state(); +} + +RID GodotPhysicsServer2D::area_create() { + GodotArea2D *area = memnew(GodotArea2D); + RID rid = area_owner.make_rid(area); + area->set_self(rid); + return rid; +} + +void GodotPhysicsServer2D::area_set_space(RID p_area, RID p_space) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + GodotSpace2D *space = nullptr; + if (p_space.is_valid()) { + space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + } + + if (area->get_space() == space) { + return; //pointless + } + + area->clear_constraints(); + area->set_space(space); +} + +RID GodotPhysicsServer2D::area_get_space(RID p_area) const { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, RID()); + + GodotSpace2D *space = area->get_space(); + if (!space) { + return RID(); + } + return space->get_self(); +} + +void GodotPhysicsServer2D::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + + area->add_shape(shape, p_transform, p_disabled); +} + +void GodotPhysicsServer2D::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + ERR_FAIL_COND(!shape->is_configured()); + + area->set_shape(p_shape_idx, shape); +} + +void GodotPhysicsServer2D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_shape_transform(p_shape_idx, p_transform); +} + +void GodotPhysicsServer2D::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + ERR_FAIL_INDEX(p_shape, area->get_shape_count()); + FLUSH_QUERY_CHECK(area); + + area->set_shape_disabled(p_shape, p_disabled); +} + +int GodotPhysicsServer2D::area_get_shape_count(RID p_area) const { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, -1); + + return area->get_shape_count(); +} + +RID GodotPhysicsServer2D::area_get_shape(RID p_area, int p_shape_idx) const { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, RID()); + + GodotShape2D *shape = area->get_shape(p_shape_idx); + ERR_FAIL_COND_V(!shape, RID()); + + return shape->get_self(); +} + +Transform2D GodotPhysicsServer2D::area_get_shape_transform(RID p_area, int p_shape_idx) const { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, Transform2D()); + + return area->get_shape_transform(p_shape_idx); +} + +void GodotPhysicsServer2D::area_remove_shape(RID p_area, int p_shape_idx) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->remove_shape(p_shape_idx); +} + +void GodotPhysicsServer2D::area_clear_shapes(RID p_area) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + while (area->get_shape_count()) { + area->remove_shape(0); + } +} + +void GodotPhysicsServer2D::area_attach_object_instance_id(RID p_area, ObjectID p_id) { + if (space_owner.owns(p_area)) { + GodotSpace2D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + area->set_instance_id(p_id); +} + +ObjectID GodotPhysicsServer2D::area_get_object_instance_id(RID p_area) const { + if (space_owner.owns(p_area)) { + GodotSpace2D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, ObjectID()); + return area->get_instance_id(); +} + +void GodotPhysicsServer2D::area_attach_canvas_instance_id(RID p_area, ObjectID p_id) { + if (space_owner.owns(p_area)) { + GodotSpace2D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + area->set_canvas_instance_id(p_id); +} + +ObjectID GodotPhysicsServer2D::area_get_canvas_instance_id(RID p_area) const { + if (space_owner.owns(p_area)) { + GodotSpace2D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, ObjectID()); + return area->get_canvas_instance_id(); +} + +void GodotPhysicsServer2D::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) { + if (space_owner.owns(p_area)) { + GodotSpace2D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + area->set_param(p_param, p_value); +}; + +void GodotPhysicsServer2D::area_set_transform(RID p_area, const Transform2D &p_transform) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + area->set_transform(p_transform); +}; + +Variant GodotPhysicsServer2D::area_get_param(RID p_area, AreaParameter p_param) const { + if (space_owner.owns(p_area)) { + GodotSpace2D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, Variant()); + + return area->get_param(p_param); +}; + +Transform2D GodotPhysicsServer2D::area_get_transform(RID p_area) const { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, Transform2D()); + + return area->get_transform(); +}; + +void GodotPhysicsServer2D::area_set_pickable(RID p_area, bool p_pickable) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + area->set_pickable(p_pickable); +} + +void GodotPhysicsServer2D::area_set_monitorable(RID p_area, bool p_monitorable) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + FLUSH_QUERY_CHECK(area); + + area->set_monitorable(p_monitorable); +} + +void GodotPhysicsServer2D::area_set_collision_mask(RID p_area, uint32_t p_mask) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_collision_mask(p_mask); +} + +void GodotPhysicsServer2D::area_set_collision_layer(RID p_area, uint32_t p_layer) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_collision_layer(p_layer); +} + +void GodotPhysicsServer2D::area_set_monitor_callback(RID p_area, const Callable &p_callback) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_monitor_callback(p_callback.is_valid() ? p_callback : Callable()); +} + +void GodotPhysicsServer2D::area_set_area_monitor_callback(RID p_area, const Callable &p_callback) { + GodotArea2D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_area_monitor_callback(p_callback.is_valid() ? p_callback : Callable()); +} + +/* BODY API */ + +RID GodotPhysicsServer2D::body_create() { + GodotBody2D *body = memnew(GodotBody2D); + RID rid = body_owner.make_rid(body); + body->set_self(rid); + return rid; +} + +void GodotPhysicsServer2D::body_set_space(RID p_body, RID p_space) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + GodotSpace2D *space = nullptr; + if (p_space.is_valid()) { + space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + } + + if (body->get_space() == space) { + return; //pointless + } + + body->clear_constraint_list(); + body->set_space(space); +}; + +RID GodotPhysicsServer2D::body_get_space(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, RID()); + + GodotSpace2D *space = body->get_space(); + if (!space) { + return RID(); + } + return space->get_self(); +}; + +void GodotPhysicsServer2D::body_set_mode(RID p_body, BodyMode p_mode) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + FLUSH_QUERY_CHECK(body); + + body->set_mode(p_mode); +}; + +PhysicsServer2D::BodyMode GodotPhysicsServer2D::body_get_mode(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, BODY_MODE_STATIC); + + return body->get_mode(); +}; + +void GodotPhysicsServer2D::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + + body->add_shape(shape, p_transform, p_disabled); +} + +void GodotPhysicsServer2D::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + GodotShape2D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + ERR_FAIL_COND(!shape->is_configured()); + + body->set_shape(p_shape_idx, shape); +} + +void GodotPhysicsServer2D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_shape_transform(p_shape_idx, p_transform); +} + +int GodotPhysicsServer2D::body_get_shape_count(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, -1); + + return body->get_shape_count(); +} + +RID GodotPhysicsServer2D::body_get_shape(RID p_body, int p_shape_idx) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, RID()); + + GodotShape2D *shape = body->get_shape(p_shape_idx); + ERR_FAIL_COND_V(!shape, RID()); + + return shape->get_self(); +} + +Transform2D GodotPhysicsServer2D::body_get_shape_transform(RID p_body, int p_shape_idx) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, Transform2D()); + + return body->get_shape_transform(p_shape_idx); +} + +void GodotPhysicsServer2D::body_remove_shape(RID p_body, int p_shape_idx) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->remove_shape(p_shape_idx); +} + +void GodotPhysicsServer2D::body_clear_shapes(RID p_body) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + while (body->get_shape_count()) { + body->remove_shape(0); + } +} + +void GodotPhysicsServer2D::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); + FLUSH_QUERY_CHECK(body); + + body->set_shape_disabled(p_shape_idx, p_disabled); +} + +void GodotPhysicsServer2D::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); + FLUSH_QUERY_CHECK(body); + + body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin); +} + +void GodotPhysicsServer2D::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_continuous_collision_detection_mode(p_mode); +} + +GodotPhysicsServer2D::CCDMode GodotPhysicsServer2D::body_get_continuous_collision_detection_mode(RID p_body) const { + const GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, CCD_MODE_DISABLED); + + return body->get_continuous_collision_detection_mode(); +} + +void GodotPhysicsServer2D::body_attach_object_instance_id(RID p_body, ObjectID p_id) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_instance_id(p_id); +}; + +ObjectID GodotPhysicsServer2D::body_get_object_instance_id(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, ObjectID()); + + return body->get_instance_id(); +}; + +void GodotPhysicsServer2D::body_attach_canvas_instance_id(RID p_body, ObjectID p_id) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_canvas_instance_id(p_id); +}; + +ObjectID GodotPhysicsServer2D::body_get_canvas_instance_id(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, ObjectID()); + + return body->get_canvas_instance_id(); +}; + +void GodotPhysicsServer2D::body_set_collision_layer(RID p_body, uint32_t p_layer) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_collision_layer(p_layer); +}; + +uint32_t GodotPhysicsServer2D::body_get_collision_layer(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_layer(); +}; + +void GodotPhysicsServer2D::body_set_collision_mask(RID p_body, uint32_t p_mask) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_collision_mask(p_mask); +}; + +uint32_t GodotPhysicsServer2D::body_get_collision_mask(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_mask(); +}; + +void GodotPhysicsServer2D::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_param(p_param, p_value); +}; + +Variant GodotPhysicsServer2D::body_get_param(RID p_body, BodyParameter p_param) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_param(p_param); +}; + +void GodotPhysicsServer2D::body_reset_mass_properties(RID p_body) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + return body->reset_mass_properties(); +} + +void GodotPhysicsServer2D::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_state(p_state, p_variant); +}; + +Variant GodotPhysicsServer2D::body_get_state(RID p_body, BodyState p_state) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, Variant()); + + return body->get_state(p_state); +}; + +void GodotPhysicsServer2D::body_set_applied_force(RID p_body, const Vector2 &p_force) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_applied_force(p_force); + body->wakeup(); +}; + +Vector2 GodotPhysicsServer2D::body_get_applied_force(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, Vector2()); + return body->get_applied_force(); +}; + +void GodotPhysicsServer2D::body_set_applied_torque(RID p_body, real_t p_torque) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_applied_torque(p_torque); + body->wakeup(); +}; + +real_t GodotPhysicsServer2D::body_get_applied_torque(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_applied_torque(); +}; + +void GodotPhysicsServer2D::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->apply_central_impulse(p_impulse); + body->wakeup(); +} + +void GodotPhysicsServer2D::body_apply_torque_impulse(RID p_body, real_t p_torque) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + body->apply_torque_impulse(p_torque); + body->wakeup(); +} + +void GodotPhysicsServer2D::body_apply_impulse(RID p_body, const Vector2 &p_impulse, const Vector2 &p_position) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + body->apply_impulse(p_impulse, p_position); + body->wakeup(); +}; + +void GodotPhysicsServer2D::body_add_central_force(RID p_body, const Vector2 &p_force) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->add_central_force(p_force); + body->wakeup(); +}; + +void GodotPhysicsServer2D::body_add_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->add_force(p_force, p_position); + body->wakeup(); +}; + +void GodotPhysicsServer2D::body_add_torque(RID p_body, real_t p_torque) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->add_torque(p_torque); + body->wakeup(); +}; + +void GodotPhysicsServer2D::body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + Vector2 v = body->get_linear_velocity(); + Vector2 axis = p_axis_velocity.normalized(); + v -= axis * axis.dot(v); + v += p_axis_velocity; + body->set_linear_velocity(v); + body->wakeup(); +}; + +void GodotPhysicsServer2D::body_add_collision_exception(RID p_body, RID p_body_b) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->add_exception(p_body_b); + body->wakeup(); +}; + +void GodotPhysicsServer2D::body_remove_collision_exception(RID p_body, RID p_body_b) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->remove_exception(p_body_b); + body->wakeup(); +}; + +void GodotPhysicsServer2D::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + for (int i = 0; i < body->get_exceptions().size(); i++) { + p_exceptions->push_back(body->get_exceptions()[i]); + } +}; + +void GodotPhysicsServer2D::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); +}; + +real_t GodotPhysicsServer2D::body_get_contacts_reported_depth_threshold(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + return 0; +}; + +void GodotPhysicsServer2D::body_set_omit_force_integration(RID p_body, bool p_omit) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_omit_force_integration(p_omit); +}; + +bool GodotPhysicsServer2D::body_is_omitting_force_integration(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, false); + return body->get_omit_force_integration(); +}; + +void GodotPhysicsServer2D::body_set_max_contacts_reported(RID p_body, int p_contacts) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_max_contacts_reported(p_contacts); +} + +int GodotPhysicsServer2D::body_get_max_contacts_reported(RID p_body) const { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, -1); + return body->get_max_contacts_reported(); +} + +void GodotPhysicsServer2D::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_state_sync_callback(p_instance, p_callback); +} + +void GodotPhysicsServer2D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_force_integration_callback(p_callable, p_udata); +} + +bool GodotPhysicsServer2D::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, false); + ERR_FAIL_INDEX_V(p_body_shape, body->get_shape_count(), false); + + return shape_collide(body->get_shape(p_body_shape)->get_self(), body->get_transform() * body->get_shape_transform(p_body_shape), Vector2(), p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count); +} + +void GodotPhysicsServer2D::body_set_pickable(RID p_body, bool p_pickable) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_pickable(p_pickable); +} + +bool GodotPhysicsServer2D::body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result) { + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, false); + ERR_FAIL_COND_V(!body->get_space(), false); + ERR_FAIL_COND_V(body->get_space()->is_locked(), false); + + _update_shapes(); + + return body->get_space()->test_body_motion(body, p_parameters, r_result); +} + +PhysicsDirectBodyState2D *GodotPhysicsServer2D::body_get_direct_state(RID p_body) { + ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); + + if (!body_owner.owns(p_body)) { + return nullptr; + } + + GodotBody2D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, nullptr); + + if (!body->get_space()) { + return nullptr; + } + + ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); + + return body->get_direct_state(); +} + +/* JOINT API */ + +RID GodotPhysicsServer2D::joint_create() { + GodotJoint2D *joint = memnew(GodotJoint2D); + RID joint_rid = joint_owner.make_rid(joint); + joint->set_self(joint_rid); + return joint_rid; +} + +void GodotPhysicsServer2D::joint_clear(RID p_joint) { + GodotJoint2D *joint = joint_owner.get_or_null(p_joint); + if (joint->get_type() != JOINT_TYPE_MAX) { + GodotJoint2D *empty_joint = memnew(GodotJoint2D); + empty_joint->copy_settings_from(joint); + + joint_owner.replace(p_joint, empty_joint); + memdelete(joint); + } +} + +void GodotPhysicsServer2D::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) { + GodotJoint2D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + + switch (p_param) { + case JOINT_PARAM_BIAS: + joint->set_bias(p_value); + break; + case JOINT_PARAM_MAX_BIAS: + joint->set_max_bias(p_value); + break; + case JOINT_PARAM_MAX_FORCE: + joint->set_max_force(p_value); + break; + } +} + +real_t GodotPhysicsServer2D::joint_get_param(RID p_joint, JointParam p_param) const { + const GodotJoint2D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, -1); + + switch (p_param) { + case JOINT_PARAM_BIAS: + return joint->get_bias(); + break; + case JOINT_PARAM_MAX_BIAS: + return joint->get_max_bias(); + break; + case JOINT_PARAM_MAX_FORCE: + return joint->get_max_force(); + break; + } + + return 0; +} + +void GodotPhysicsServer2D::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { + GodotJoint2D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + + joint->disable_collisions_between_bodies(p_disable); + + if (2 == joint->get_body_count()) { + GodotBody2D *body_a = *joint->get_body_ptr(); + GodotBody2D *body_b = *(joint->get_body_ptr() + 1); + + if (p_disable) { + body_add_collision_exception(body_a->get_self(), body_b->get_self()); + body_add_collision_exception(body_b->get_self(), body_a->get_self()); + } else { + body_remove_collision_exception(body_a->get_self(), body_b->get_self()); + body_remove_collision_exception(body_b->get_self(), body_a->get_self()); + } + } +} + +bool GodotPhysicsServer2D::joint_is_disabled_collisions_between_bodies(RID p_joint) const { + const GodotJoint2D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, true); + + return joint->is_disabled_collisions_between_bodies(); +} + +void GodotPhysicsServer2D::joint_make_pin(RID p_joint, const Vector2 &p_pos, RID p_body_a, RID p_body_b) { + GodotBody2D *A = body_owner.get_or_null(p_body_a); + ERR_FAIL_COND(!A); + GodotBody2D *B = nullptr; + if (body_owner.owns(p_body_b)) { + B = body_owner.get_or_null(p_body_b); + ERR_FAIL_COND(!B); + } + + GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint2D *joint = memnew(GodotPinJoint2D(p_pos, A, B)); + + joint_owner.replace(p_joint, joint); + joint->copy_settings_from(prev_joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer2D::joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) { + GodotBody2D *A = body_owner.get_or_null(p_body_a); + ERR_FAIL_COND(!A); + + GodotBody2D *B = body_owner.get_or_null(p_body_b); + ERR_FAIL_COND(!B); + + GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint2D *joint = memnew(GodotGrooveJoint2D(p_a_groove1, p_a_groove2, p_b_anchor, A, B)); + + joint_owner.replace(p_joint, joint); + joint->copy_settings_from(prev_joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer2D::joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) { + GodotBody2D *A = body_owner.get_or_null(p_body_a); + ERR_FAIL_COND(!A); + + GodotBody2D *B = body_owner.get_or_null(p_body_b); + ERR_FAIL_COND(!B); + + GodotJoint2D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint2D *joint = memnew(GodotDampedSpringJoint2D(p_anchor_a, p_anchor_b, A, B)); + + joint_owner.replace(p_joint, joint); + joint->copy_settings_from(prev_joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer2D::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { + GodotJoint2D *j = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!j); + ERR_FAIL_COND(j->get_type() != JOINT_TYPE_PIN); + + GodotPinJoint2D *pin_joint = static_cast<GodotPinJoint2D *>(j); + pin_joint->set_param(p_param, p_value); +} + +real_t GodotPhysicsServer2D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { + GodotJoint2D *j = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!j, 0); + ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_PIN, 0); + + GodotPinJoint2D *pin_joint = static_cast<GodotPinJoint2D *>(j); + return pin_joint->get_param(p_param); +} + +void GodotPhysicsServer2D::damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) { + GodotJoint2D *j = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!j); + ERR_FAIL_COND(j->get_type() != JOINT_TYPE_DAMPED_SPRING); + + GodotDampedSpringJoint2D *dsj = static_cast<GodotDampedSpringJoint2D *>(j); + dsj->set_param(p_param, p_value); +} + +real_t GodotPhysicsServer2D::damped_spring_joint_get_param(RID p_joint, DampedSpringParam p_param) const { + GodotJoint2D *j = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!j, 0); + ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_DAMPED_SPRING, 0); + + GodotDampedSpringJoint2D *dsj = static_cast<GodotDampedSpringJoint2D *>(j); + return dsj->get_param(p_param); +} + +PhysicsServer2D::JointType GodotPhysicsServer2D::joint_get_type(RID p_joint) const { + GodotJoint2D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN); + + return joint->get_type(); +} + +void GodotPhysicsServer2D::free(RID p_rid) { + _update_shapes(); // just in case + + if (shape_owner.owns(p_rid)) { + GodotShape2D *shape = shape_owner.get_or_null(p_rid); + + while (shape->get_owners().size()) { + GodotShapeOwner2D *so = shape->get_owners().front()->key(); + so->remove_shape(shape); + } + + shape_owner.free(p_rid); + memdelete(shape); + } else if (body_owner.owns(p_rid)) { + GodotBody2D *body = body_owner.get_or_null(p_rid); + + /* + if (body->get_state_query()) + _clear_query(body->get_state_query()); + + if (body->get_direct_state_query()) + _clear_query(body->get_direct_state_query()); + */ + + body_set_space(p_rid, RID()); + + while (body->get_shape_count()) { + body->remove_shape(0); + } + + body_owner.free(p_rid); + memdelete(body); + + } else if (area_owner.owns(p_rid)) { + GodotArea2D *area = area_owner.get_or_null(p_rid); + + /* + if (area->get_monitor_query()) + _clear_query(area->get_monitor_query()); + */ + + area->set_space(nullptr); + + while (area->get_shape_count()) { + area->remove_shape(0); + } + + area_owner.free(p_rid); + memdelete(area); + } else if (space_owner.owns(p_rid)) { + GodotSpace2D *space = space_owner.get_or_null(p_rid); + + while (space->get_objects().size()) { + GodotCollisionObject2D *co = (GodotCollisionObject2D *)space->get_objects().front()->get(); + co->set_space(nullptr); + } + + active_spaces.erase(space); + free(space->get_default_area()->get_self()); + space_owner.free(p_rid); + memdelete(space); + } else if (joint_owner.owns(p_rid)) { + GodotJoint2D *joint = joint_owner.get_or_null(p_rid); + + joint_owner.free(p_rid); + memdelete(joint); + + } else { + ERR_FAIL_MSG("Invalid ID."); + } +}; + +void GodotPhysicsServer2D::set_active(bool p_active) { + active = p_active; +}; + +void GodotPhysicsServer2D::set_collision_iterations(int p_iterations) { + iterations = p_iterations; +}; + +void GodotPhysicsServer2D::init() { + doing_sync = false; + iterations = 8; // 8? + stepper = memnew(GodotStep2D); +}; + +void GodotPhysicsServer2D::step(real_t p_step) { + if (!active) { + return; + } + + _update_shapes(); + + island_count = 0; + active_objects = 0; + collision_pairs = 0; + for (Set<const GodotSpace2D *>::Element *E = active_spaces.front(); E; E = E->next()) { + stepper->step((GodotSpace2D *)E->get(), p_step, iterations); + island_count += E->get()->get_island_count(); + active_objects += E->get()->get_active_objects(); + collision_pairs += E->get()->get_collision_pairs(); + } +}; + +void GodotPhysicsServer2D::sync() { + doing_sync = true; +}; + +void GodotPhysicsServer2D::flush_queries() { + if (!active) { + return; + } + + flushing_queries = true; + + uint64_t time_beg = OS::get_singleton()->get_ticks_usec(); + + for (Set<const GodotSpace2D *>::Element *E = active_spaces.front(); E; E = E->next()) { + GodotSpace2D *space = (GodotSpace2D *)E->get(); + space->call_queries(); + } + + flushing_queries = false; + + if (EngineDebugger::is_profiling("servers")) { + uint64_t total_time[GodotSpace2D::ELAPSED_TIME_MAX]; + static const char *time_name[GodotSpace2D::ELAPSED_TIME_MAX] = { + "integrate_forces", + "generate_islands", + "setup_constraints", + "solve_constraints", + "integrate_velocities" + }; + + for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) { + total_time[i] = 0; + } + + for (Set<const GodotSpace2D *>::Element *E = active_spaces.front(); E; E = E->next()) { + for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) { + total_time[i] += E->get()->get_elapsed_time(GodotSpace2D::ElapsedTime(i)); + } + } + + Array values; + values.resize(GodotSpace2D::ELAPSED_TIME_MAX * 2); + for (int i = 0; i < GodotSpace2D::ELAPSED_TIME_MAX; i++) { + values[i * 2 + 0] = time_name[i]; + values[i * 2 + 1] = USEC_TO_SEC(total_time[i]); + } + values.push_back("flush_queries"); + values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg)); + + values.push_front("physics_2d"); + EngineDebugger::profiler_add_frame_data("servers", values); + } +} + +void GodotPhysicsServer2D::end_sync() { + doing_sync = false; +} + +void GodotPhysicsServer2D::finish() { + memdelete(stepper); +}; + +void GodotPhysicsServer2D::_update_shapes() { + while (pending_shape_update_list.first()) { + pending_shape_update_list.first()->self()->_shape_changed(); + pending_shape_update_list.remove(pending_shape_update_list.first()); + } +} + +int GodotPhysicsServer2D::get_process_info(ProcessInfo p_info) { + switch (p_info) { + case INFO_ACTIVE_OBJECTS: { + return active_objects; + } break; + case INFO_COLLISION_PAIRS: { + return collision_pairs; + } break; + case INFO_ISLAND_COUNT: { + return island_count; + } break; + } + + return 0; +} + +GodotPhysicsServer2D *GodotPhysicsServer2D::godot_singleton = nullptr; + +GodotPhysicsServer2D::GodotPhysicsServer2D(bool p_using_threads) { + godot_singleton = this; + GodotBroadPhase2D::create_func = GodotBroadPhase2DBVH::_create; + + using_threads = p_using_threads; +}; diff --git a/servers/physics_2d/physics_server_2d_sw.h b/servers/physics_2d/godot_physics_server_2d.h index ef1306cf59..1f544fee72 100644 --- a/servers/physics_2d/physics_server_2d_sw.h +++ b/servers/physics_2d/godot_physics_server_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* physics_server_2d_sw.h */ +/* godot_physics_server_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,47 +28,47 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PHYSICS_2D_SERVER_SW -#define PHYSICS_2D_SERVER_SW +#ifndef GODOT_PHYSICS_SERVER_2D_H +#define GODOT_PHYSICS_SERVER_2D_H + +#include "godot_joints_2d.h" +#include "godot_shape_2d.h" +#include "godot_space_2d.h" +#include "godot_step_2d.h" #include "core/templates/rid_owner.h" -#include "joints_2d_sw.h" #include "servers/physics_server_2d.h" -#include "shape_2d_sw.h" -#include "space_2d_sw.h" -#include "step_2d_sw.h" -class PhysicsServer2DSW : public PhysicsServer2D { - GDCLASS(PhysicsServer2DSW, PhysicsServer2D); +class GodotPhysicsServer2D : public PhysicsServer2D { + GDCLASS(GodotPhysicsServer2D, PhysicsServer2D); - friend class PhysicsDirectSpaceState2DSW; - friend class PhysicsDirectBodyState2DSW; - bool active; - int iterations; - bool doing_sync; + friend class GodotPhysicsDirectSpaceState2D; + friend class GodotPhysicsDirectBodyState2D; + bool active = true; + int iterations = 0; + bool doing_sync = false; - int island_count; - int active_objects; - int collision_pairs; + int island_count = 0; + int active_objects = 0; + int collision_pairs = 0; - bool using_threads; + bool using_threads = false; - bool flushing_queries; + bool flushing_queries = false; - Step2DSW *stepper; - Set<const Space2DSW *> active_spaces; + GodotStep2D *stepper = nullptr; + Set<const GodotSpace2D *> active_spaces; - mutable RID_PtrOwner<Shape2DSW, true> shape_owner; - mutable RID_PtrOwner<Space2DSW, true> space_owner; - mutable RID_PtrOwner<Area2DSW, true> area_owner; - mutable RID_PtrOwner<Body2DSW, true> body_owner; - mutable RID_PtrOwner<Joint2DSW, true> joint_owner; + mutable RID_PtrOwner<GodotShape2D, true> shape_owner; + mutable RID_PtrOwner<GodotSpace2D, true> space_owner; + mutable RID_PtrOwner<GodotArea2D, true> area_owner; + mutable RID_PtrOwner<GodotBody2D, true> body_owner; + mutable RID_PtrOwner<GodotJoint2D, true> joint_owner; - static PhysicsServer2DSW *singletonsw; + static GodotPhysicsServer2D *godot_singleton; - //void _clear_query(Query2DSW *p_query); - friend class CollisionObject2DSW; - SelfList<CollisionObject2DSW>::List pending_shape_update_list; + friend class GodotCollisionObject2D; + SelfList<GodotCollisionObject2D>::List pending_shape_update_list; void _update_shapes(); RID _shape_create(ShapeType p_shape); @@ -76,15 +76,15 @@ class PhysicsServer2DSW : public PhysicsServer2D { public: struct CollCbkData { Vector2 valid_dir; - real_t valid_depth; - int max; - int amount; - int passed; - int invalid_by_dir; - Vector2 *ptr; + real_t valid_depth = 0.0; + int max = 0; + int amount = 0; + int passed = 0; + int invalid_by_dir = 0; + Vector2 *ptr = nullptr; }; - virtual RID world_margin_shape_create() override; + virtual RID world_boundary_shape_create() override; virtual RID separation_ray_shape_create() override; virtual RID segment_shape_create() override; virtual RID circle_shape_create() override; @@ -124,9 +124,6 @@ public: virtual RID area_create() override; - virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) override; - virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const override; - virtual void area_set_space(RID p_area, RID p_space) override; virtual RID area_get_space(RID p_area) const override; @@ -158,8 +155,8 @@ public: virtual void area_set_collision_mask(RID p_area, uint32_t p_mask) override; virtual void area_set_collision_layer(RID p_area, uint32_t p_layer) override; - virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override; - virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override; + virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) override; + virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) override; virtual void area_set_pickable(RID p_area, bool p_pickable) override; @@ -177,12 +174,10 @@ public: virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) override; virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) override; virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) override; - virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) override; virtual int body_get_shape_count(RID p_body) const override; virtual RID body_get_shape(RID p_body, int p_shape_idx) const override; virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const override; - virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const override; virtual void body_remove_shape(RID p_body, int p_shape_idx) override; virtual void body_clear_shapes(RID p_body) override; @@ -205,8 +200,10 @@ public: virtual void body_set_collision_mask(RID p_body, uint32_t p_mask) override; virtual uint32_t body_get_collision_mask(RID p_body) const override; - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override; + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override; + + virtual void body_reset_mass_properties(RID p_body) override; virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override; virtual Variant body_get_state(RID p_body, BodyState p_state) const override; @@ -246,7 +243,7 @@ public: virtual void body_set_pickable(RID p_body, bool p_pickable) override; - virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override; + virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override; // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) override; @@ -292,8 +289,8 @@ public: int get_process_info(ProcessInfo p_info) override; - PhysicsServer2DSW(bool p_using_threads = false); - ~PhysicsServer2DSW() {} + GodotPhysicsServer2D(bool p_using_threads = false); + ~GodotPhysicsServer2D() {} }; -#endif +#endif // GODOT_PHYSICS_SERVER_2D_H diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/godot_shape_2d.cpp index 064c4afe52..3604004324 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/godot_shape_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* shape_2d_sw.cpp */ +/* godot_shape_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,29 +28,29 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "shape_2d_sw.h" +#include "godot_shape_2d.h" #include "core/math/geometry_2d.h" #include "core/templates/sort_array.h" -void Shape2DSW::configure(const Rect2 &p_aabb) { +void GodotShape2D::configure(const Rect2 &p_aabb) { aabb = p_aabb; configured = true; - for (Map<ShapeOwner2DSW *, int>::Element *E = owners.front(); E; E = E->next()) { - ShapeOwner2DSW *co = (ShapeOwner2DSW *)E->key(); + for (const KeyValue<GodotShapeOwner2D *, int> &E : owners) { + GodotShapeOwner2D *co = (GodotShapeOwner2D *)E.key; co->_shape_changed(); } } -Vector2 Shape2DSW::get_support(const Vector2 &p_normal) const { +Vector2 GodotShape2D::get_support(const Vector2 &p_normal) const { Vector2 res[2]; int amnt; get_supports(p_normal, res, amnt); return res[0]; } -void Shape2DSW::add_owner(ShapeOwner2DSW *p_owner) { - Map<ShapeOwner2DSW *, int>::Element *E = owners.find(p_owner); +void GodotShape2D::add_owner(GodotShapeOwner2D *p_owner) { + Map<GodotShapeOwner2D *, int>::Element *E = owners.find(p_owner); if (E) { E->get()++; } else { @@ -58,8 +58,8 @@ void Shape2DSW::add_owner(ShapeOwner2DSW *p_owner) { } } -void Shape2DSW::remove_owner(ShapeOwner2DSW *p_owner) { - Map<ShapeOwner2DSW *, int>::Element *E = owners.find(p_owner); +void GodotShape2D::remove_owner(GodotShapeOwner2D *p_owner) { + Map<GodotShapeOwner2D *, int>::Element *E = owners.find(p_owner); ERR_FAIL_COND(!E); E->get()--; if (E->get() == 0) { @@ -67,20 +67,15 @@ void Shape2DSW::remove_owner(ShapeOwner2DSW *p_owner) { } } -bool Shape2DSW::is_owner(ShapeOwner2DSW *p_owner) const { +bool GodotShape2D::is_owner(GodotShapeOwner2D *p_owner) const { return owners.has(p_owner); } -const Map<ShapeOwner2DSW *, int> &Shape2DSW::get_owners() const { +const Map<GodotShapeOwner2D *, int> &GodotShape2D::get_owners() const { return owners; } -Shape2DSW::Shape2DSW() { - custom_bias = 0; - configured = false; -} - -Shape2DSW::~Shape2DSW() { +GodotShape2D::~GodotShape2D() { ERR_FAIL_COND(owners.size()); } @@ -88,15 +83,15 @@ Shape2DSW::~Shape2DSW() { /*********************************************************/ /*********************************************************/ -void WorldMarginShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void GodotWorldBoundaryShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { r_amount = 0; } -bool WorldMarginShape2DSW::contains_point(const Vector2 &p_point) const { +bool GodotWorldBoundaryShape2D::contains_point(const Vector2 &p_point) const { return normal.dot(p_point) < d; } -bool WorldMarginShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool GodotWorldBoundaryShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { Vector2 segment = p_begin - p_end; real_t den = normal.dot(segment); @@ -118,11 +113,11 @@ bool WorldMarginShape2DSW::intersect_segment(const Vector2 &p_begin, const Vecto return true; } -real_t WorldMarginShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t GodotWorldBoundaryShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { return 0; } -void WorldMarginShape2DSW::set_data(const Variant &p_data) { +void GodotWorldBoundaryShape2D::set_data(const Variant &p_data) { ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY); Array arr = p_data; ERR_FAIL_COND(arr.size() != 2); @@ -131,7 +126,7 @@ void WorldMarginShape2DSW::set_data(const Variant &p_data) { configure(Rect2(Vector2(-1e4, -1e4), Vector2(1e4 * 2, 1e4 * 2))); } -Variant WorldMarginShape2DSW::get_data() const { +Variant GodotWorldBoundaryShape2D::get_data() const { Array arr; arr.resize(2); arr[0] = normal; @@ -143,7 +138,7 @@ Variant WorldMarginShape2DSW::get_data() const { /*********************************************************/ /*********************************************************/ -void SeparationRayShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void GodotSeparationRayShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { r_amount = 1; if (p_normal.y > 0) { @@ -153,26 +148,26 @@ void SeparationRayShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_su } } -bool SeparationRayShape2DSW::contains_point(const Vector2 &p_point) const { +bool GodotSeparationRayShape2D::contains_point(const Vector2 &p_point) const { return false; } -bool SeparationRayShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool GodotSeparationRayShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { return false; //rays can't be intersected } -real_t SeparationRayShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t GodotSeparationRayShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { return 0; //rays are mass-less } -void SeparationRayShape2DSW::set_data(const Variant &p_data) { +void GodotSeparationRayShape2D::set_data(const Variant &p_data) { Dictionary d = p_data; length = d["length"]; slide_on_slope = d["slide_on_slope"]; configure(Rect2(0, 0, 0.001, length)); } -Variant SeparationRayShape2DSW::get_data() const { +Variant GodotSeparationRayShape2D::get_data() const { Dictionary d; d["length"] = length; d["slide_on_slope"] = slide_on_slope; @@ -183,7 +178,7 @@ Variant SeparationRayShape2DSW::get_data() const { /*********************************************************/ /*********************************************************/ -void SegmentShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void GodotSegmentShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { if (Math::abs(p_normal.dot(n)) > _SEGMENT_IS_VALID_SUPPORT_THRESHOLD) { r_supports[0] = a; r_supports[1] = b; @@ -200,11 +195,11 @@ void SegmentShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports r_amount = 1; } -bool SegmentShape2DSW::contains_point(const Vector2 &p_point) const { +bool GodotSegmentShape2D::contains_point(const Vector2 &p_point) const { return false; } -bool SegmentShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool GodotSegmentShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { if (!Geometry2D::segment_intersects_segment(p_begin, p_end, a, b, &r_point)) { return false; } @@ -218,11 +213,11 @@ bool SegmentShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 & return true; } -real_t SegmentShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t GodotSegmentShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { return p_mass * ((a * p_scale).distance_squared_to(b * p_scale)) / 12; } -void SegmentShape2DSW::set_data(const Variant &p_data) { +void GodotSegmentShape2D::set_data(const Variant &p_data) { ERR_FAIL_COND(p_data.get_type() != Variant::RECT2); Rect2 r = p_data; @@ -242,7 +237,7 @@ void SegmentShape2DSW::set_data(const Variant &p_data) { configure(aabb); } -Variant SegmentShape2DSW::get_data() const { +Variant GodotSegmentShape2D::get_data() const { Rect2 r; r.position = a; r.size = b; @@ -253,16 +248,16 @@ Variant SegmentShape2DSW::get_data() const { /*********************************************************/ /*********************************************************/ -void CircleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void GodotCircleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { r_amount = 1; *r_supports = p_normal * radius; } -bool CircleShape2DSW::contains_point(const Vector2 &p_point) const { +bool GodotCircleShape2D::contains_point(const Vector2 &p_point) const { return p_point.length_squared() < radius * radius; } -bool CircleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool GodotCircleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { Vector2 line_vec = p_end - p_begin; real_t a, b, c; @@ -288,19 +283,19 @@ bool CircleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p return true; } -real_t CircleShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t GodotCircleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { real_t a = radius * p_scale.x; real_t b = radius * p_scale.y; return p_mass * (a * a + b * b) / 4; } -void CircleShape2DSW::set_data(const Variant &p_data) { +void GodotCircleShape2D::set_data(const Variant &p_data) { ERR_FAIL_COND(!p_data.is_num()); radius = p_data; configure(Rect2(-radius, -radius, radius * 2, radius * 2)); } -Variant CircleShape2DSW::get_data() const { +Variant GodotCircleShape2D::get_data() const { return radius; } @@ -308,7 +303,7 @@ Variant CircleShape2DSW::get_data() const { /*********************************************************/ /*********************************************************/ -void RectangleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void GodotRectangleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { for (int i = 0; i < 2; i++) { Vector2 ag; ag[i] = 1.0; @@ -338,7 +333,7 @@ void RectangleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_suppor (p_normal.y < 0) ? -half_extents.y : half_extents.y); } -bool RectangleShape2DSW::contains_point(const Vector2 &p_point) const { +bool GodotRectangleShape2D::contains_point(const Vector2 &p_point) const { real_t x = p_point.x; real_t y = p_point.y; real_t edge_x = half_extents.x; @@ -346,23 +341,23 @@ bool RectangleShape2DSW::contains_point(const Vector2 &p_point) const { return (x >= -edge_x) && (x < edge_x) && (y >= -edge_y) && (y < edge_y); } -bool RectangleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool GodotRectangleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { return get_aabb().intersects_segment(p_begin, p_end, &r_point, &r_normal); } -real_t RectangleShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t GodotRectangleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { Vector2 he2 = half_extents * 2 * p_scale; return p_mass * he2.dot(he2) / 12.0; } -void RectangleShape2DSW::set_data(const Variant &p_data) { +void GodotRectangleShape2D::set_data(const Variant &p_data) { ERR_FAIL_COND(p_data.get_type() != Variant::VECTOR2); half_extents = p_data; configure(Rect2(-half_extents, half_extents * 2.0)); } -Variant RectangleShape2DSW::get_data() const { +Variant GodotRectangleShape2D::get_data() const { return half_extents; } @@ -370,7 +365,7 @@ Variant RectangleShape2DSW::get_data() const { /*********************************************************/ /*********************************************************/ -void CapsuleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void GodotCapsuleShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { Vector2 n = p_normal; real_t d = n.y; @@ -397,7 +392,7 @@ void CapsuleShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports } } -bool CapsuleShape2DSW::contains_point(const Vector2 &p_point) const { +bool GodotCapsuleShape2D::contains_point(const Vector2 &p_point) const { Vector2 p = p_point; p.y = Math::abs(p.y); p.y -= height * 0.5 - radius; @@ -408,7 +403,7 @@ bool CapsuleShape2DSW::contains_point(const Vector2 &p_point) const { return p.length_squared() < radius * radius; } -bool CapsuleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool GodotCapsuleShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { real_t d = 1e10; Vector2 n = (p_end - p_begin).normalized(); bool collided = false; @@ -468,12 +463,12 @@ bool CapsuleShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 & return collided; //todo } -real_t CapsuleShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t GodotCapsuleShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { Vector2 he2 = Vector2(radius * 2, height) * p_scale; return p_mass * he2.dot(he2) / 12.0; } -void CapsuleShape2DSW::set_data(const Variant &p_data) { +void GodotCapsuleShape2D::set_data(const Variant &p_data) { ERR_FAIL_COND(p_data.get_type() != Variant::ARRAY && p_data.get_type() != Variant::VECTOR2); if (p_data.get_type() == Variant::ARRAY) { @@ -491,7 +486,7 @@ void CapsuleShape2DSW::set_data(const Variant &p_data) { configure(Rect2(-he, he * 2)); } -Variant CapsuleShape2DSW::get_data() const { +Variant GodotCapsuleShape2D::get_data() const { return Point2(height, radius); } @@ -499,7 +494,7 @@ Variant CapsuleShape2DSW::get_data() const { /*********************************************************/ /*********************************************************/ -void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void GodotConvexPolygonShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { int support_idx = -1; real_t d = -1e10; r_amount = 0; @@ -527,7 +522,7 @@ void ConvexPolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_su r_supports[0] = points[support_idx].pos; } -bool ConvexPolygonShape2DSW::contains_point(const Vector2 &p_point) const { +bool GodotConvexPolygonShape2D::contains_point(const Vector2 &p_point) const { bool out = false; bool in = false; @@ -543,7 +538,7 @@ bool ConvexPolygonShape2DSW::contains_point(const Vector2 &p_point) const { return in != out; } -bool ConvexPolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool GodotConvexPolygonShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { Vector2 n = (p_end - p_begin).normalized(); real_t d = 1e10; bool inters = false; @@ -573,7 +568,7 @@ bool ConvexPolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vec return inters; } -real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { +real_t GodotConvexPolygonShape2D::get_moment_of_inertia(real_t p_mass, const Size2 &p_scale) const { ERR_FAIL_COND_V_MSG(point_count == 0, 0, "Convex polygon shape has no points."); Rect2 aabb; aabb.position = points[0].pos * p_scale; @@ -584,7 +579,7 @@ real_t ConvexPolygonShape2DSW::get_moment_of_inertia(real_t p_mass, const Size2 return p_mass * aabb.size.dot(aabb.size) / 12.0; } -void ConvexPolygonShape2DSW::set_data(const Variant &p_data) { +void GodotConvexPolygonShape2D::set_data(const Variant &p_data) { #ifdef REAL_T_IS_DOUBLE ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT64_ARRAY); #else @@ -640,7 +635,7 @@ void ConvexPolygonShape2DSW::set_data(const Variant &p_data) { configure(aabb); } -Variant ConvexPolygonShape2DSW::get_data() const { +Variant GodotConvexPolygonShape2D::get_data() const { Vector<Vector2> dvr; dvr.resize(point_count); @@ -652,12 +647,7 @@ Variant ConvexPolygonShape2DSW::get_data() const { return dvr; } -ConvexPolygonShape2DSW::ConvexPolygonShape2DSW() { - points = nullptr; - point_count = 0; -} - -ConvexPolygonShape2DSW::~ConvexPolygonShape2DSW() { +GodotConvexPolygonShape2D::~GodotConvexPolygonShape2D() { if (points) { memdelete_arr(points); } @@ -665,7 +655,7 @@ ConvexPolygonShape2DSW::~ConvexPolygonShape2DSW() { ////////////////////////////////////////////////// -void ConcavePolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { +void GodotConcavePolygonShape2D::get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const { real_t d = -1e10; int idx = -1; for (int i = 0; i < points.size(); i++) { @@ -681,11 +671,11 @@ void ConcavePolygonShape2DSW::get_supports(const Vector2 &p_normal, Vector2 *r_s *r_supports = points[idx]; } -bool ConcavePolygonShape2DSW::contains_point(const Vector2 &p_point) const { +bool GodotConcavePolygonShape2D::contains_point(const Vector2 &p_point) const { return false; //sorry } -bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { +bool GodotConcavePolygonShape2D::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const { if (segments.size() == 0 || points.size() == 0) { return false; } @@ -793,7 +783,7 @@ bool ConcavePolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Ve return inters; } -int ConcavePolygonShape2DSW::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) { +int GodotConcavePolygonShape2D::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) { if (p_len == 1) { bvh_depth = MAX(p_depth, bvh_depth); bvh.push_back(*p_bvh); @@ -831,7 +821,7 @@ int ConcavePolygonShape2DSW::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) { return node_idx; } -void ConcavePolygonShape2DSW::set_data(const Variant &p_data) { +void GodotConcavePolygonShape2D::set_data(const Variant &p_data) { #ifdef REAL_T_IS_DOUBLE ERR_FAIL_COND(p_data.get_type() != Variant::PACKED_VECTOR2_ARRAY && p_data.get_type() != Variant::PACKED_FLOAT64_ARRAY); #else @@ -885,9 +875,9 @@ void ConcavePolygonShape2DSW::set_data(const Variant &p_data) { points.resize(pointmap.size()); aabb.position = pointmap.front()->key(); - for (Map<Point2, int>::Element *E = pointmap.front(); E; E = E->next()) { - aabb.expand_to(E->key()); - points.write[E->get()] = E->key(); + for (const KeyValue<Point2, int> &E : pointmap) { + aabb.expand_to(E.key); + points.write[E.value] = E.key; } Vector<BVH> main_vbh; @@ -908,7 +898,7 @@ void ConcavePolygonShape2DSW::set_data(const Variant &p_data) { configure(aabb); } -Variant ConcavePolygonShape2DSW::get_data() const { +Variant GodotConcavePolygonShape2D::get_data() const { Vector<Vector2> rsegments; int len = segments.size(); rsegments.resize(len * 2); @@ -921,7 +911,7 @@ Variant ConcavePolygonShape2DSW::get_data() const { return rsegments; } -void ConcavePolygonShape2DSW::cull(const Rect2 &p_local_aabb, QueryCallback p_callback, void *p_userdata) const { +void GodotConcavePolygonShape2D::cull(const Rect2 &p_local_aabb, QueryCallback p_callback, void *p_userdata) const { uint32_t *stack = (uint32_t *)alloca(sizeof(int) * bvh_depth); enum { @@ -967,7 +957,7 @@ void ConcavePolygonShape2DSW::cull(const Rect2 &p_local_aabb, QueryCallback p_ca Vector2 a = pointptr[s.points[0]]; Vector2 b = pointptr[s.points[1]]; - SegmentShape2DSW ss(a, b, (b - a).orthogonal().normalized()); + GodotSegmentShape2D ss(a, b, (b - a).orthogonal().normalized()); if (p_callback(p_userdata, &ss)) { return; diff --git a/servers/physics_2d/shape_2d_sw.h b/servers/physics_2d/godot_shape_2d.h index 1185d343ee..25d113aafb 100644 --- a/servers/physics_2d/shape_2d_sw.h +++ b/servers/physics_2d/godot_shape_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* shape_2d_sw.h */ +/* godot_shape_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,29 +28,29 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SHAPE_2D_2DSW_H -#define SHAPE_2D_2DSW_H +#ifndef GODOT_SHAPE_2D_H +#define GODOT_SHAPE_2D_H #include "servers/physics_server_2d.h" #define _SEGMENT_IS_VALID_SUPPORT_THRESHOLD 0.99998 -class Shape2DSW; +class GodotShape2D; -class ShapeOwner2DSW { +class GodotShapeOwner2D { public: virtual void _shape_changed() = 0; - virtual void remove_shape(Shape2DSW *p_shape) = 0; + virtual void remove_shape(GodotShape2D *p_shape) = 0; - virtual ~ShapeOwner2DSW() {} + virtual ~GodotShapeOwner2D() {} }; -class Shape2DSW { +class GodotShape2D { RID self; Rect2 aabb; - bool configured; - real_t custom_bias; + bool configured = false; + real_t custom_bias = 0.0; - Map<ShapeOwner2DSW *, int> owners; + Map<GodotShapeOwner2D *, int> owners; protected: void configure(const Rect2 &p_aabb); @@ -83,10 +83,10 @@ public: _FORCE_INLINE_ void set_custom_bias(real_t p_bias) { custom_bias = p_bias; } _FORCE_INLINE_ real_t get_custom_bias() const { return custom_bias; } - void add_owner(ShapeOwner2DSW *p_owner); - void remove_owner(ShapeOwner2DSW *p_owner); - bool is_owner(ShapeOwner2DSW *p_owner) const; - const Map<ShapeOwner2DSW *, int> &get_owners() const; + void add_owner(GodotShapeOwner2D *p_owner); + void remove_owner(GodotShapeOwner2D *p_owner); + bool is_owner(GodotShapeOwner2D *p_owner) const; + const Map<GodotShapeOwner2D *, int> &get_owners() const; _FORCE_INLINE_ void get_supports_transformed_cast(const Vector2 &p_cast, const Vector2 &p_normal, const Transform2D &p_xform, Vector2 *r_supports, int &r_amount) const { get_supports(p_xform.basis_xform_inv(p_normal).normalized(), r_supports, r_amount); @@ -121,9 +121,8 @@ public: } } } - - Shape2DSW(); - virtual ~Shape2DSW(); + GodotShape2D() {} + virtual ~GodotShape2D(); }; //let the optimizer do the magic @@ -142,15 +141,15 @@ public: r_max = MAX(maxa, maxb); \ } -class WorldMarginShape2DSW : public Shape2DSW { +class GodotWorldBoundaryShape2D : public GodotShape2D { Vector2 normal; - real_t d; + real_t d = 0.0; public: _FORCE_INLINE_ Vector2 get_normal() const { return normal; } _FORCE_INLINE_ real_t get_d() const { return d; } - virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_WORLD_MARGIN; } + virtual PhysicsServer2D::ShapeType get_type() const override { return PhysicsServer2D::SHAPE_WORLD_BOUNDARY; } virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { project_range(p_normal, p_transform, r_min, r_max); } virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override; @@ -179,9 +178,9 @@ public: } }; -class SeparationRayShape2DSW : public Shape2DSW { - real_t length; - bool slide_on_slope; +class GodotSeparationRayShape2D : public GodotShape2D { + real_t length = 0.0; + bool slide_on_slope = false; public: _FORCE_INLINE_ real_t get_length() const { return length; } @@ -212,11 +211,11 @@ public: DEFAULT_PROJECT_RANGE_CAST - _FORCE_INLINE_ SeparationRayShape2DSW() {} - _FORCE_INLINE_ SeparationRayShape2DSW(real_t p_length) { length = p_length; } + _FORCE_INLINE_ GodotSeparationRayShape2D() {} + _FORCE_INLINE_ GodotSeparationRayShape2D(real_t p_length) { length = p_length; } }; -class SegmentShape2DSW : public Shape2DSW { +class GodotSegmentShape2D : public GodotShape2D { Vector2 a; Vector2 b; Vector2 n; @@ -252,15 +251,15 @@ public: DEFAULT_PROJECT_RANGE_CAST - _FORCE_INLINE_ SegmentShape2DSW() {} - _FORCE_INLINE_ SegmentShape2DSW(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_n) { + _FORCE_INLINE_ GodotSegmentShape2D() {} + _FORCE_INLINE_ GodotSegmentShape2D(const Vector2 &p_a, const Vector2 &p_b, const Vector2 &p_n) { a = p_a; b = p_b; n = p_n; } }; -class CircleShape2DSW : public Shape2DSW { +class GodotCircleShape2D : public GodotShape2D { real_t radius; public: @@ -293,7 +292,7 @@ public: DEFAULT_PROJECT_RANGE_CAST }; -class RectangleShape2DSW : public Shape2DSW { +class GodotRectangleShape2D : public GodotShape2D { Vector2 half_extents; public: @@ -337,7 +336,7 @@ public: return (p_xform.xform(he) - p_circle).normalized(); } - _FORCE_INLINE_ Vector2 get_box_axis(const Transform2D &p_xform, const Transform2D &p_xform_inv, const RectangleShape2DSW *p_B, const Transform2D &p_B_xform, const Transform2D &p_B_xform_inv) const { + _FORCE_INLINE_ Vector2 get_box_axis(const Transform2D &p_xform, const Transform2D &p_xform_inv, const GodotRectangleShape2D *p_B, const Transform2D &p_B_xform, const Transform2D &p_B_xform_inv) const { Vector2 a, b; { @@ -365,9 +364,9 @@ public: DEFAULT_PROJECT_RANGE_CAST }; -class CapsuleShape2DSW : public Shape2DSW { - real_t radius; - real_t height; +class GodotCapsuleShape2D : public GodotShape2D { + real_t radius = 0.0; + real_t height = 0.0; public: _FORCE_INLINE_ const real_t &get_radius() const { return radius; } @@ -406,14 +405,14 @@ public: DEFAULT_PROJECT_RANGE_CAST }; -class ConvexPolygonShape2DSW : public Shape2DSW { +class GodotConvexPolygonShape2D : public GodotShape2D { struct Point { Vector2 pos; Vector2 normal; //normal to next segment }; - Point *points; - int point_count; + Point *points = nullptr; + int point_count = 0; public: _FORCE_INLINE_ int get_point_count() const { return point_count; } @@ -458,23 +457,23 @@ public: DEFAULT_PROJECT_RANGE_CAST - ConvexPolygonShape2DSW(); - ~ConvexPolygonShape2DSW(); + GodotConvexPolygonShape2D() {} + ~GodotConvexPolygonShape2D(); }; -class ConcaveShape2DSW : public Shape2DSW { +class GodotConcaveShape2D : public GodotShape2D { public: virtual bool is_concave() const override { return true; } // Returns true to stop the query. - typedef bool (*QueryCallback)(void *p_userdata, Shape2DSW *p_convex); + typedef bool (*QueryCallback)(void *p_userdata, GodotShape2D *p_convex); virtual void cull(const Rect2 &p_local_aabb, QueryCallback p_callback, void *p_userdata) const = 0; }; -class ConcavePolygonShape2DSW : public ConcaveShape2DSW { +class GodotConcavePolygonShape2D : public GodotConcaveShape2D { struct Segment { - int points[2]; + int points[2] = {}; }; Vector<Segment> segments; @@ -482,11 +481,11 @@ class ConcavePolygonShape2DSW : public ConcaveShape2DSW { struct BVH { Rect2 aabb; - int left, right; + int left = 0, right = 0; }; Vector<BVH> bvh; - int bvh_depth; + int bvh_depth = 0; struct BVH_CompareX { _FORCE_INLINE_ bool operator()(const BVH &a, const BVH &b) const { @@ -508,13 +507,13 @@ public: virtual void project_rangev(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const override { r_min = 0; r_max = 0; - ERR_FAIL_MSG("Unsupported call to project_rangev in ConcavePolygonShape2DSW"); + ERR_FAIL_MSG("Unsupported call to project_rangev in GodotConcavePolygonShape2D"); } void project_range(const Vector2 &p_normal, const Transform2D &p_transform, real_t &r_min, real_t &r_max) const { r_min = 0; r_max = 0; - ERR_FAIL_MSG("Unsupported call to project_range in ConcavePolygonShape2DSW"); + ERR_FAIL_MSG("Unsupported call to project_range in GodotConcavePolygonShape2D"); } virtual void get_supports(const Vector2 &p_normal, Vector2 *r_supports, int &r_amount) const override; @@ -534,4 +533,4 @@ public: #undef DEFAULT_PROJECT_RANGE_CAST -#endif // SHAPE_2D_2DSW_H +#endif // GODOT_SHAPE_2D_H diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/godot_space_2d.cpp index 6c23f49928..7a5eb26bb3 100644 --- a/servers/physics_2d/space_2d_sw.cpp +++ b/servers/physics_2d/godot_space_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* space_2d_sw.cpp */ +/* godot_space_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,65 +28,69 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "space_2d_sw.h" +#include "godot_space_2d.h" + +#include "godot_collision_solver_2d.h" +#include "godot_physics_server_2d.h" -#include "collision_solver_2d_sw.h" #include "core/os/os.h" #include "core/templates/pair.h" -#include "physics_server_2d_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) { + +#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05 + +_FORCE_INLINE_ static bool _can_collide_with(GodotCollisionObject2D *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)) { return false; } - if (p_object->get_type() == CollisionObject2DSW::TYPE_AREA && !p_collide_with_areas) { + if (p_object->get_type() == GodotCollisionObject2D::TYPE_AREA && !p_collide_with_areas) { return false; } - if (p_object->get_type() == CollisionObject2DSW::TYPE_BODY && !p_collide_with_bodies) { + if (p_object->get_type() == GodotCollisionObject2D::TYPE_BODY && !p_collide_with_bodies) { return false; } return true; } -int PhysicsDirectSpaceState2DSW::_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) { +int GodotPhysicsDirectSpaceState2D::intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) { if (p_result_max <= 0) { return 0; } Rect2 aabb; - aabb.position = p_point - Vector2(0.00001, 0.00001); + aabb.position = p_parameters.position - Vector2(0.00001, 0.00001); aabb.size = Vector2(0.00002, 0.00002); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); int cc = 0; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - if (p_exclude.has(space->intersection_query_results[i]->get_self())) { + if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) { continue; } - const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject2D *col_obj = space->intersection_query_results[i]; - if (p_pick_point && !col_obj->is_pickable()) { + if (p_parameters.pick_point && !col_obj->is_pickable()) { continue; } - if (p_filter_by_canvas && col_obj->get_canvas_instance_id() != p_canvas_instance_id) { + if (p_parameters.canvas_instance_id.is_valid() && col_obj->get_canvas_instance_id() != p_parameters.canvas_instance_id) { continue; } int shape_idx = space->intersection_query_subindex_results[i]; - Shape2DSW *shape = col_obj->get_shape(shape_idx); + GodotShape2D *shape = col_obj->get_shape(shape_idx); - Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_point); + Vector2 local_point = (col_obj->get_transform() * col_obj->get_shape_transform(shape_idx)).affine_inverse().xform(p_parameters.position); if (!shape->contains_point(local_point)) { continue; @@ -102,7 +106,6 @@ int PhysicsDirectSpaceState2DSW::_intersect_point_impl(const Vector2 &p_point, S } r_results[cc].rid = col_obj->get_self(); r_results[cc].shape = shape_idx; - r_results[cc].metadata = col_obj->get_shape_metadata(shape_idx); cc++; } @@ -110,43 +113,35 @@ int PhysicsDirectSpaceState2DSW::_intersect_point_impl(const Vector2 &p_point, S return cc; } -int PhysicsDirectSpaceState2DSW::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 PhysicsDirectSpaceState2DSW::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 PhysicsDirectSpaceState2DSW::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) { +bool GodotPhysicsDirectSpaceState2D::intersect_ray(const RayParameters &p_parameters, RayResult &r_result) { ERR_FAIL_COND_V(space->locked, false); Vector2 begin, end; Vector2 normal; - begin = p_from; - end = p_to; + begin = p_parameters.from; + end = p_parameters.to; normal = (end - begin).normalized(); - int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); //todo, create another array that references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision bool collided = false; Vector2 res_point, res_normal; int res_shape; - const CollisionObject2DSW *res_obj; + const GodotCollisionObject2D *res_obj; real_t min_d = 1e10; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - if (p_exclude.has(space->intersection_query_results[i]->get_self())) { + if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) { continue; } - const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject2D *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; Transform2D inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform(); @@ -154,16 +149,26 @@ bool PhysicsDirectSpaceState2DSW::intersect_ray(const Vector2 &p_from, const Vec Vector2 local_from = inv_xform.xform(begin); Vector2 local_to = inv_xform.xform(end); - /*local_from = col_obj->get_inv_transform().xform(begin); - local_from = col_obj->get_shape_inv_transform(shape_idx).xform(local_from); - - local_to = col_obj->get_inv_transform().xform(end); - local_to = col_obj->get_shape_inv_transform(shape_idx).xform(local_to);*/ - - const Shape2DSW *shape = col_obj->get_shape(shape_idx); + const GodotShape2D *shape = col_obj->get_shape(shape_idx); Vector2 shape_point, shape_normal; + if (shape->contains_point(local_from)) { + if (p_parameters.hit_from_inside) { + // Hit shape at starting point. + min_d = 0; + res_point = local_from; + res_normal = Vector2(); + res_shape = shape_idx; + res_obj = col_obj; + collided = true; + break; + } else { + // Ignore shape when starting inside. + continue; + } + } + if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) { Transform2D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); shape_point = xform.xform(shape_point); @@ -190,7 +195,6 @@ bool PhysicsDirectSpaceState2DSW::intersect_ray(const Vector2 &p_from, const Vec r_result.collider = ObjectDB::get_instance(r_result.collider_id); } r_result.normal = res_normal; - r_result.metadata = res_obj->get_shape_metadata(res_shape); r_result.position = res_point; r_result.rid = res_obj->get_self(); r_result.shape = res_shape; @@ -198,18 +202,19 @@ bool PhysicsDirectSpaceState2DSW::intersect_ray(const Vector2 &p_from, const Vec return true; } -int PhysicsDirectSpaceState2DSW::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, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +int GodotPhysicsDirectSpaceState2D::intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) { if (p_result_max <= 0) { return 0; } - Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape); + GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, 0); - Rect2 aabb = p_xform.xform(shape->get_aabb()); - aabb = aabb.grow(p_margin); + Rect2 aabb = p_parameters.transform.xform(shape->get_aabb()); + aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion + aabb = aabb.grow(p_parameters.margin); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); int cc = 0; @@ -218,18 +223,18 @@ int PhysicsDirectSpaceState2DSW::intersect_shape(const RID &p_shape, const Trans break; } - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - if (p_exclude.has(space->intersection_query_results[i]->get_self())) { + if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) { continue; } - const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject2D *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; - if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), nullptr, nullptr, nullptr, p_margin)) { + if (!GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), nullptr, nullptr, nullptr, p_parameters.margin)) { continue; } @@ -239,7 +244,6 @@ int PhysicsDirectSpaceState2DSW::intersect_shape(const RID &p_shape, const Trans } r_results[cc].rid = col_obj->get_self(); r_results[cc].shape = shape_idx; - r_results[cc].metadata = col_obj->get_shape_metadata(shape_idx); cc++; } @@ -247,43 +251,43 @@ int PhysicsDirectSpaceState2DSW::intersect_shape(const RID &p_shape, const Trans return cc; } -bool PhysicsDirectSpaceState2DSW::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, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { - Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape); +bool GodotPhysicsDirectSpaceState2D::cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe) { + GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, false); - Rect2 aabb = p_xform.xform(shape->get_aabb()); - aabb = aabb.merge(Rect2(aabb.position + p_motion, aabb.size)); //motion - aabb = aabb.grow(p_margin); + Rect2 aabb = p_parameters.transform.xform(shape->get_aabb()); + aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion + aabb = aabb.grow(p_parameters.margin); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); real_t best_safe = 1; real_t best_unsafe = 1; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - if (p_exclude.has(space->intersection_query_results[i]->get_self())) { + if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) { continue; //ignore excluded } - const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject2D *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; Transform2D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? - if (!CollisionSolver2DSW::solve(shape, p_xform, p_motion, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) { + if (!GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_parameters.margin)) { continue; } //test initial overlap, ignore objects it's inside of. - if (CollisionSolver2DSW::solve(shape, p_xform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_margin)) { + if (GodotCollisionSolver2D::solve(shape, p_parameters.transform, Vector2(), col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, nullptr, p_parameters.margin)) { continue; } - Vector2 mnormal = p_motion.normalized(); + Vector2 mnormal = p_parameters.motion.normalized(); //just do kinematic solving real_t low = 0.0; @@ -293,7 +297,7 @@ bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transfor real_t fraction = low + (hi - low) * fraction_coeff; Vector2 sep = mnormal; //important optimization for this to work fast enough - bool collided = CollisionSolver2DSW::solve(shape, p_xform, p_motion * fraction, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, &sep, p_margin); + bool collided = GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion * fraction, col_obj->get_shape(shape_idx), col_obj_xform, Vector2(), nullptr, nullptr, &sep, p_parameters.margin); if (collided) { hi = fraction; @@ -330,40 +334,40 @@ bool PhysicsDirectSpaceState2DSW::cast_motion(const RID &p_shape, const Transfor return true; } -bool PhysicsDirectSpaceState2DSW::collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool GodotPhysicsDirectSpaceState2D::collide_shape(const ShapeParameters &p_parameters, Vector2 *r_results, int p_result_max, int &r_result_count) { if (p_result_max <= 0) { return false; } - Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape); + GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, 0); - Rect2 aabb = p_shape_xform.xform(shape->get_aabb()); - aabb = aabb.merge(Rect2(aabb.position + p_motion, aabb.size)); //motion - aabb = aabb.grow(p_margin); + Rect2 aabb = p_parameters.transform.xform(shape->get_aabb()); + aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion + aabb = aabb.grow(p_parameters.margin); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); bool collided = false; r_result_count = 0; - PhysicsServer2DSW::CollCbkData cbk; + GodotPhysicsServer2D::CollCbkData cbk; cbk.max = p_result_max; cbk.amount = 0; cbk.passed = 0; cbk.ptr = r_results; - CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk; + GodotCollisionSolver2D::CallbackResult cbkres = GodotPhysicsServer2D::_shape_col_cbk; - PhysicsServer2DSW::CollCbkData *cbkptr = &cbk; + GodotPhysicsServer2D::CollCbkData *cbkptr = &cbk; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject2D *col_obj = space->intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + if (p_parameters.exclude.has(col_obj->get_self())) { continue; } @@ -372,7 +376,7 @@ bool PhysicsDirectSpaceState2DSW::collide_shape(RID p_shape, const Transform2D & cbk.valid_dir = Vector2(); cbk.valid_depth = 0; - if (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(), cbkres, cbkptr, nullptr, p_margin)) { + if (GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, nullptr, p_parameters.margin)) { collided = cbk.amount > 0; } } @@ -383,18 +387,18 @@ bool PhysicsDirectSpaceState2DSW::collide_shape(RID p_shape, const Transform2D & } struct _RestCallbackData2D { - const CollisionObject2DSW *object; - const CollisionObject2DSW *best_object; - int local_shape; - int best_local_shape; - int shape; - int best_shape; + const GodotCollisionObject2D *object = nullptr; + const GodotCollisionObject2D *best_object = nullptr; + int local_shape = 0; + int best_local_shape = 0; + int shape = 0; + int best_shape = 0; Vector2 best_contact; Vector2 best_normal; - real_t best_len; + real_t best_len = 0.0; Vector2 valid_dir; - real_t valid_depth; - real_t min_allowed_depth; + real_t valid_depth = 0.0; + real_t min_allowed_depth = 0.0; }; static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) { @@ -431,30 +435,31 @@ static void _rest_cbk_result(const Vector2 &p_point_A, const Vector2 &p_point_B, rd->best_local_shape = rd->local_shape; } -bool PhysicsDirectSpaceState2DSW::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) { - Shape2DSW *shape = PhysicsServer2DSW::singletonsw->shape_owner.getornull(p_shape); +bool GodotPhysicsDirectSpaceState2D::rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) { + GodotShape2D *shape = GodotPhysicsServer2D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, 0); - Rect2 aabb = p_shape_xform.xform(shape->get_aabb()); - aabb = aabb.merge(Rect2(aabb.position + p_motion, aabb.size)); //motion - aabb = aabb.grow(p_margin); + Rect2 aabb = p_parameters.transform.xform(shape->get_aabb()); + aabb = aabb.merge(Rect2(aabb.position + p_parameters.motion, aabb.size)); //motion + aabb = aabb.grow(p_parameters.margin); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space2DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace2D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); _RestCallbackData2D rcd; - rcd.best_len = 0; - rcd.best_object = nullptr; - rcd.best_shape = 0; - rcd.min_allowed_depth = space->test_motion_min_contact_depth; + + // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. + real_t motion_length = p_parameters.motion.length(); + real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; + rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - const CollisionObject2DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject2D *col_obj = space->intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + if (p_parameters.exclude.has(col_obj->get_self())) { continue; } @@ -464,7 +469,7 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh 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, nullptr, p_margin); + bool sc = GodotCollisionSolver2D::solve(shape, p_parameters.transform, p_parameters.motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), _rest_cbk_result, &rcd, nullptr, p_parameters.margin); if (!sc) { continue; } @@ -479,10 +484,9 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh r_info->normal = rcd.best_normal; r_info->point = rcd.best_contact; r_info->rid = rcd.best_object->get_self(); - r_info->metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); - if (rcd.best_object->get_type() == CollisionObject2DSW::TYPE_BODY) { - const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object); - Vector2 rel_vec = r_info->point - body->get_transform().get_origin(); + if (rcd.best_object->get_type() == GodotCollisionObject2D::TYPE_BODY) { + const GodotBody2D *body = static_cast<const GodotBody2D *>(rcd.best_object); + Vector2 rel_vec = r_info->point - (body->get_transform().get_origin() + body->get_center_of_mass()); r_info->linear_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); } else { @@ -492,13 +496,9 @@ bool PhysicsDirectSpaceState2DSW::rest_info(RID p_shape, const Transform2D &p_sh return true; } -PhysicsDirectSpaceState2DSW::PhysicsDirectSpaceState2DSW() { - space = nullptr; -} - //////////////////////////////////////////////////////////////////////////////////////////////////////////// -int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) { +int GodotSpace2D::_cull_aabb_for_body(GodotBody2D *p_body, const Rect2 &p_aabb) { int amount = broadphase->cull_aabb(p_aabb, intersection_query_results, INTERSECTION_QUERY_MAX, intersection_query_subindex_results); for (int i = 0; i < amount; i++) { @@ -506,11 +506,11 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) { if (intersection_query_results[i] == p_body) { keep = false; - } else if (intersection_query_results[i]->get_type() == CollisionObject2DSW::TYPE_AREA) { + } else if (intersection_query_results[i]->get_type() == GodotCollisionObject2D::TYPE_AREA) { keep = false; - } else if (!p_body->collides_with(static_cast<Body2DSW *>(intersection_query_results[i]))) { + } else if (!p_body->collides_with(static_cast<GodotBody2D *>(intersection_query_results[i]))) { keep = false; - } else if (static_cast<Body2DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) { + } else if (static_cast<GodotBody2D *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) { keep = false; } @@ -528,7 +528,7 @@ int Space2DSW::_cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb) { return amount; } -bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_collide_separation_ray, const Set<RID> &p_exclude) { +bool GodotSpace2D::test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult *r_result) { //give me back regular physics engine logic //this is madness //and most people using this function will think @@ -560,23 +560,25 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (!shapes_found) { if (r_result) { *r_result = PhysicsServer2D::MotionResult(); - r_result->travel = p_motion; + r_result->travel = p_parameters.motion; } return false; } // Undo the currently transform the physics server is aware of and apply the provided one - body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb)); - body_aabb = body_aabb.grow(p_margin); + body_aabb = p_parameters.from.xform(p_body->get_inv_transform().xform(body_aabb)); + body_aabb = body_aabb.grow(p_parameters.margin); static const int max_excluded_shape_pairs = 32; ExcludedShapeSW excluded_shape_pairs[max_excluded_shape_pairs]; int excluded_shape_pair_count = 0; - real_t motion_length = p_motion.length(); - Vector2 motion_normal = p_motion / motion_length; + real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; - Transform2D body_transform = p_from; + real_t motion_length = p_parameters.motion.length(); + Vector2 motion_normal = p_parameters.motion / motion_length; + + Transform2D body_transform = p_parameters.from; bool recovered = false; @@ -588,7 +590,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co Vector2 sr[max_results * 2]; do { - PhysicsServer2DSW::CollCbkData cbk; + GodotPhysicsServer2D::CollCbkData cbk; cbk.max = max_results; cbk.amount = 0; cbk.passed = 0; @@ -596,8 +598,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co cbk.invalid_by_dir = 0; excluded_shape_pair_count = 0; //last step is the one valid - PhysicsServer2DSW::CollCbkData *cbkptr = &cbk; - CollisionSolver2DSW::CallbackResult cbkres = PhysicsServer2DSW::_shape_col_cbk; + GodotPhysicsServer2D::CollCbkData *cbkptr = &cbk; + GodotCollisionSolver2D::CallbackResult cbkres = GodotPhysicsServer2D::_shape_col_cbk; bool collided = false; @@ -608,12 +610,15 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co continue; } - Shape2DSW *body_shape = p_body->get_shape(j); + GodotShape2D *body_shape = p_body->get_shape(j); Transform2D body_shape_xform = body_transform * p_body->get_shape_transform(j); for (int i = 0; i < amount; i++) { - const CollisionObject2DSW *col_obj = intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + const GodotCollisionObject2D *col_obj = intersection_query_results[i]; + if (p_parameters.exclude_bodies.has(col_obj->get_self())) { + continue; + } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { continue; } @@ -625,11 +630,11 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co cbk.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx); - cbk.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work + cbk.valid_depth = MAX(owc_margin, p_parameters.margin); //user specified, but never less than actual margin or it won't work cbk.invalid_by_dir = 0; - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { - const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); + if (col_obj->get_type() == GodotCollisionObject2D::TYPE_BODY) { + const GodotBody2D *b = static_cast<const GodotBody2D *>(col_obj); if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) { //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(); @@ -649,8 +654,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co int current_passed = cbk.passed; //save how many points passed collision 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_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_margin)) { + GodotShape2D *against_shape = col_obj->get_shape(shape_idx); + if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), cbkres, cbkptr, nullptr, p_parameters.margin)) { did_collide = cbk.passed > current_passed; //more passed, so collision actually existed } @@ -675,6 +680,8 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co break; } + recovered = true; + Vector2 recover_motion; for (int i = 0; i < cbk.amount; i++) { Vector2 a = sr[i * 2 + 0]; @@ -686,9 +693,9 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co // Compute depth on recovered motion. real_t depth = n.dot(a + recover_motion) - d; - if (depth > 0.0) { + if (depth > min_contact_depth + CMP_EPSILON) { // Only recover if there is penetration. - recover_motion -= n * depth * 0.4; + recover_motion -= n * (depth - min_contact_depth) * 0.4; } } @@ -697,8 +704,6 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co break; } - recovered = true; - body_transform.elements[2] += recover_motion; body_aabb.position += recover_motion; @@ -715,7 +720,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co // STEP 2 ATTEMPT MOTION Rect2 motion_aabb = body_aabb; - motion_aabb.position += p_motion; + motion_aabb.position += p_parameters.motion; motion_aabb = motion_aabb.merge(body_aabb); int amount = _cull_aabb_for_body(p_body, motion_aabb); @@ -725,13 +730,13 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co continue; } - Shape2DSW *body_shape = p_body->get_shape(body_shape_idx); + GodotShape2D *body_shape = p_body->get_shape(body_shape_idx); // Colliding separation rays allows to properly snap to the ground, // otherwise it's not needed in regular motion. - if (!p_collide_separation_ray && (body_shape->get_type() == PhysicsServer2D::SHAPE_SEPARATION_RAY)) { + if (!p_parameters.collide_separation_ray && (body_shape->get_type() == PhysicsServer2D::SHAPE_SEPARATION_RAY)) { // When slide on slope is on, separation ray shape acts like a regular shape. - if (!static_cast<SeparationRayShape2DSW *>(body_shape)->get_slide_on_slope()) { + if (!static_cast<GodotSeparationRayShape2D *>(body_shape)->get_slide_on_slope()) { continue; } } @@ -744,12 +749,16 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co real_t best_unsafe = 1; for (int i = 0; i < amount; i++) { - const CollisionObject2DSW *col_obj = intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + const GodotCollisionObject2D *col_obj = intersection_query_results[i]; + if (p_parameters.exclude_bodies.has(col_obj->get_self())) { continue; } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { + continue; + } + int col_shape_idx = intersection_query_subindex_results[i]; - Shape2DSW *against_shape = col_obj->get_shape(col_shape_idx); + GodotShape2D *against_shape = col_obj->get_shape(col_shape_idx); bool excluded = false; @@ -766,12 +775,12 @@ 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(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_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) { + if (!GodotCollisionSolver2D::solve(body_shape, body_shape_xform, p_parameters.motion, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) { continue; } //test initial overlap - if (CollisionSolver2DSW::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) { + if (GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, nullptr, 0)) { if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) { Vector2 direction = col_obj_shape_xform.get_axis(1).normalized(); if (motion_normal.dot(direction) < 0) { @@ -791,7 +800,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co real_t fraction = low + (hi - low) * fraction_coeff; Vector2 sep = motion_normal; //important optimization for this to work fast enough - bool collided = CollisionSolver2DSW::solve(body_shape, body_shape_xform, p_motion * fraction, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0); + bool collided = GodotCollisionSolver2D::solve(body_shape, body_shape_xform, p_parameters.motion * fraction, against_shape, col_obj_shape_xform, Vector2(), nullptr, nullptr, &sep, 0); if (collided) { hi = fraction; @@ -818,7 +827,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co if (body_shape->allows_one_way_collision() && col_obj->is_shape_set_as_one_way_collision(col_shape_idx)) { Vector2 cd[2]; - PhysicsServer2DSW::CollCbkData cbk; + GodotPhysicsServer2D::CollCbkData cbk; cbk.max = 1; cbk.amount = 0; cbk.passed = 0; @@ -828,7 +837,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co cbk.valid_depth = 10e20; Vector2 sep = motion_normal; //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_shape_xform, Vector2(), PhysicsServer2DSW::_shape_col_cbk, &cbk, &sep, 0); + bool collided = GodotCollisionSolver2D::solve(body_shape, body_shape_xform, p_parameters.motion * (hi + contact_max_allowed_penetration), col_obj->get_shape(col_shape_idx), col_obj_shape_xform, Vector2(), GodotPhysicsServer2D::_shape_col_cbk, &cbk, &sep, 0); if (!collided || cbk.amount == 0) { continue; } @@ -866,15 +875,12 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co //it collided, let's get the rest info in unsafe advance Transform2D ugt = body_transform; - ugt.elements[2] += p_motion * unsafe; + ugt.elements[2] += p_parameters.motion * unsafe; _RestCallbackData2D rcd; - rcd.best_len = 0; - rcd.best_object = nullptr; - rcd.best_shape = 0; // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. - rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth); + rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); @@ -885,21 +891,24 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } Transform2D body_shape_xform = ugt * p_body->get_shape_transform(j); - Shape2DSW *body_shape = p_body->get_shape(j); + GodotShape2D *body_shape = p_body->get_shape(j); - body_aabb.position += p_motion * unsafe; + body_aabb.position += p_parameters.motion * unsafe; int amount = _cull_aabb_for_body(p_body, body_aabb); for (int i = 0; i < amount; i++) { - const CollisionObject2DSW *col_obj = intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + const GodotCollisionObject2D *col_obj = intersection_query_results[i]; + if (p_parameters.exclude_bodies.has(col_obj->get_self())) { + continue; + } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { continue; } int shape_idx = intersection_query_subindex_results[i]; - Shape2DSW *against_shape = col_obj->get_shape(shape_idx); + GodotShape2D *against_shape = col_obj->get_shape(shape_idx); bool excluded = false; for (int k = 0; k < excluded_shape_pair_count; k++) { @@ -918,10 +927,10 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co rcd.valid_dir = col_obj_shape_xform.get_axis(1).normalized(); real_t owc_margin = col_obj->get_shape_one_way_collision_margin(shape_idx); - rcd.valid_depth = MAX(owc_margin, p_margin); //user specified, but never less than actual margin or it won't work + rcd.valid_depth = MAX(owc_margin, p_parameters.margin); //user specified, but never less than actual margin or it won't work - if (col_obj->get_type() == CollisionObject2DSW::TYPE_BODY) { - const Body2DSW *b = static_cast<const Body2DSW *>(col_obj); + if (col_obj->get_type() == GodotCollisionObject2D::TYPE_BODY) { + const GodotBody2D *b = static_cast<const GodotBody2D *>(col_obj); if (b->get_mode() == PhysicsServer2D::BODY_MODE_KINEMATIC || b->get_mode() == PhysicsServer2D::BODY_MODE_DYNAMIC) { //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(); @@ -940,7 +949,7 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co 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, nullptr, p_margin); + bool sc = GodotCollisionSolver2D::solve(body_shape, body_shape_xform, Vector2(), against_shape, col_obj_shape_xform, Vector2(), _rest_cbk_result, &rcd, nullptr, p_parameters.margin); if (!sc) { continue; } @@ -958,15 +967,14 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co r_result->collision_depth = rcd.best_len; r_result->collision_safe_fraction = safe; r_result->collision_unsafe_fraction = unsafe; - r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); - const Body2DSW *body = static_cast<const Body2DSW *>(rcd.best_object); - Vector2 rel_vec = r_result->collision_point - body->get_transform().get_origin(); + const GodotBody2D *body = static_cast<const GodotBody2D *>(rcd.best_object); + Vector2 rel_vec = r_result->collision_point - (body->get_transform().get_origin() + body->get_center_of_mass()); r_result->collider_velocity = Vector2(-body->get_angular_velocity() * rel_vec.y, body->get_angular_velocity() * rel_vec.x) + body->get_linear_velocity(); - r_result->travel = safe * p_motion; - r_result->remainder = p_motion - safe * p_motion; - r_result->travel += (body_transform.get_origin() - p_from.get_origin()); + r_result->travel = safe * p_parameters.motion; + r_result->remainder = p_parameters.motion - safe * p_parameters.motion; + r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin()); } collided = true; @@ -974,155 +982,155 @@ bool Space2DSW::test_body_motion(Body2DSW *p_body, const Transform2D &p_from, co } if (!collided && r_result) { - r_result->travel = p_motion; + r_result->travel = p_parameters.motion; r_result->remainder = Vector2(); - r_result->travel += (body_transform.get_origin() - p_from.get_origin()); + r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin()); } return collided; } -void *Space2DSW::_broadphase_pair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_self) { +void *GodotSpace2D::_broadphase_pair(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_self) { if (!A->interacts_with(B)) { return nullptr; } - CollisionObject2DSW::Type type_A = A->get_type(); - CollisionObject2DSW::Type type_B = B->get_type(); + GodotCollisionObject2D::Type type_A = A->get_type(); + GodotCollisionObject2D::Type type_B = B->get_type(); if (type_A > type_B) { SWAP(A, B); SWAP(p_subindex_A, p_subindex_B); SWAP(type_A, type_B); } - Space2DSW *self = (Space2DSW *)p_self; + GodotSpace2D *self = (GodotSpace2D *)p_self; self->collision_pairs++; - if (type_A == CollisionObject2DSW::TYPE_AREA) { - Area2DSW *area = static_cast<Area2DSW *>(A); - if (type_B == CollisionObject2DSW::TYPE_AREA) { - Area2DSW *area_b = static_cast<Area2DSW *>(B); - Area2Pair2DSW *area2_pair = memnew(Area2Pair2DSW(area_b, p_subindex_B, area, p_subindex_A)); + if (type_A == GodotCollisionObject2D::TYPE_AREA) { + GodotArea2D *area = static_cast<GodotArea2D *>(A); + if (type_B == GodotCollisionObject2D::TYPE_AREA) { + GodotArea2D *area_b = static_cast<GodotArea2D *>(B); + GodotArea2Pair2D *area2_pair = memnew(GodotArea2Pair2D(area_b, p_subindex_B, area, p_subindex_A)); return area2_pair; } else { - Body2DSW *body = static_cast<Body2DSW *>(B); - AreaPair2DSW *area_pair = memnew(AreaPair2DSW(body, p_subindex_B, area, p_subindex_A)); + GodotBody2D *body = static_cast<GodotBody2D *>(B); + GodotAreaPair2D *area_pair = memnew(GodotAreaPair2D(body, p_subindex_B, area, p_subindex_A)); return area_pair; } } else { - BodyPair2DSW *b = memnew(BodyPair2DSW((Body2DSW *)A, p_subindex_A, (Body2DSW *)B, p_subindex_B)); + GodotBodyPair2D *b = memnew(GodotBodyPair2D((GodotBody2D *)A, p_subindex_A, (GodotBody2D *)B, p_subindex_B)); return b; } return nullptr; } -void Space2DSW::_broadphase_unpair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_self) { +void GodotSpace2D::_broadphase_unpair(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_data, void *p_self) { if (!p_data) { return; } - Space2DSW *self = (Space2DSW *)p_self; + GodotSpace2D *self = (GodotSpace2D *)p_self; self->collision_pairs--; - Constraint2DSW *c = (Constraint2DSW *)p_data; + GodotConstraint2D *c = (GodotConstraint2D *)p_data; memdelete(c); } -const SelfList<Body2DSW>::List &Space2DSW::get_active_body_list() const { +const SelfList<GodotBody2D>::List &GodotSpace2D::get_active_body_list() const { return active_list; } -void Space2DSW::body_add_to_active_list(SelfList<Body2DSW> *p_body) { +void GodotSpace2D::body_add_to_active_list(SelfList<GodotBody2D> *p_body) { active_list.add(p_body); } -void Space2DSW::body_remove_from_active_list(SelfList<Body2DSW> *p_body) { +void GodotSpace2D::body_remove_from_active_list(SelfList<GodotBody2D> *p_body) { active_list.remove(p_body); } -void Space2DSW::body_add_to_inertia_update_list(SelfList<Body2DSW> *p_body) { - inertia_update_list.add(p_body); +void GodotSpace2D::body_add_to_mass_properties_update_list(SelfList<GodotBody2D> *p_body) { + mass_properties_update_list.add(p_body); } -void Space2DSW::body_remove_from_inertia_update_list(SelfList<Body2DSW> *p_body) { - inertia_update_list.remove(p_body); +void GodotSpace2D::body_remove_from_mass_properties_update_list(SelfList<GodotBody2D> *p_body) { + mass_properties_update_list.remove(p_body); } -BroadPhase2DSW *Space2DSW::get_broadphase() { +GodotBroadPhase2D *GodotSpace2D::get_broadphase() { return broadphase; } -void Space2DSW::add_object(CollisionObject2DSW *p_object) { +void GodotSpace2D::add_object(GodotCollisionObject2D *p_object) { ERR_FAIL_COND(objects.has(p_object)); objects.insert(p_object); } -void Space2DSW::remove_object(CollisionObject2DSW *p_object) { +void GodotSpace2D::remove_object(GodotCollisionObject2D *p_object) { ERR_FAIL_COND(!objects.has(p_object)); objects.erase(p_object); } -const Set<CollisionObject2DSW *> &Space2DSW::get_objects() const { +const Set<GodotCollisionObject2D *> &GodotSpace2D::get_objects() const { return objects; } -void Space2DSW::body_add_to_state_query_list(SelfList<Body2DSW> *p_body) { +void GodotSpace2D::body_add_to_state_query_list(SelfList<GodotBody2D> *p_body) { state_query_list.add(p_body); } -void Space2DSW::body_remove_from_state_query_list(SelfList<Body2DSW> *p_body) { +void GodotSpace2D::body_remove_from_state_query_list(SelfList<GodotBody2D> *p_body) { state_query_list.remove(p_body); } -void Space2DSW::area_add_to_monitor_query_list(SelfList<Area2DSW> *p_area) { +void GodotSpace2D::area_add_to_monitor_query_list(SelfList<GodotArea2D> *p_area) { monitor_query_list.add(p_area); } -void Space2DSW::area_remove_from_monitor_query_list(SelfList<Area2DSW> *p_area) { +void GodotSpace2D::area_remove_from_monitor_query_list(SelfList<GodotArea2D> *p_area) { monitor_query_list.remove(p_area); } -void Space2DSW::area_add_to_moved_list(SelfList<Area2DSW> *p_area) { +void GodotSpace2D::area_add_to_moved_list(SelfList<GodotArea2D> *p_area) { area_moved_list.add(p_area); } -void Space2DSW::area_remove_from_moved_list(SelfList<Area2DSW> *p_area) { +void GodotSpace2D::area_remove_from_moved_list(SelfList<GodotArea2D> *p_area) { area_moved_list.remove(p_area); } -const SelfList<Area2DSW>::List &Space2DSW::get_moved_area_list() const { +const SelfList<GodotArea2D>::List &GodotSpace2D::get_moved_area_list() const { return area_moved_list; } -void Space2DSW::call_queries() { +void GodotSpace2D::call_queries() { while (state_query_list.first()) { - Body2DSW *b = state_query_list.first()->self(); + GodotBody2D *b = state_query_list.first()->self(); state_query_list.remove(state_query_list.first()); b->call_queries(); } while (monitor_query_list.first()) { - Area2DSW *a = monitor_query_list.first()->self(); + GodotArea2D *a = monitor_query_list.first()->self(); monitor_query_list.remove(monitor_query_list.first()); a->call_queries(); } } -void Space2DSW::setup() { +void GodotSpace2D::setup() { contact_debug_count = 0; - while (inertia_update_list.first()) { - inertia_update_list.first()->self()->update_inertias(); - inertia_update_list.remove(inertia_update_list.first()); + while (mass_properties_update_list.first()) { + mass_properties_update_list.first()->self()->update_mass_properties(); + mass_properties_update_list.remove(mass_properties_update_list.first()); } } -void Space2DSW::update() { +void GodotSpace2D::update() { broadphase->update(); } -void Space2DSW::set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value) { +void GodotSpace2D::set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value) { switch (p_param) { case PhysicsServer2D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: contact_recycle_radius = p_value; @@ -1145,13 +1153,10 @@ void Space2DSW::set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_valu case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; - case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: - test_motion_min_contact_depth = p_value; - break; } } -real_t Space2DSW::get_param(PhysicsServer2D::SpaceParameter p_param) const { +real_t GodotSpace2D::get_param(PhysicsServer2D::SpaceParameter p_param) const { switch (p_param) { case PhysicsServer2D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: return contact_recycle_radius; @@ -1167,61 +1172,41 @@ real_t Space2DSW::get_param(PhysicsServer2D::SpaceParameter p_param) const { return body_time_to_sleep; case PhysicsServer2D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias; - case PhysicsServer2D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: - return test_motion_min_contact_depth; } return 0; } -void Space2DSW::lock() { +void GodotSpace2D::lock() { locked = true; } -void Space2DSW::unlock() { +void GodotSpace2D::unlock() { locked = false; } -bool Space2DSW::is_locked() const { +bool GodotSpace2D::is_locked() const { return locked; } -PhysicsDirectSpaceState2DSW *Space2DSW::get_direct_state() { +GodotPhysicsDirectSpaceState2D *GodotSpace2D::get_direct_state() { return direct_access; } -Space2DSW::Space2DSW() { - collision_pairs = 0; - active_objects = 0; - island_count = 0; - - contact_debug_count = 0; - - locked = false; - contact_recycle_radius = 1.0; - contact_max_separation = 1.5; - contact_max_allowed_penetration = 0.3; - test_motion_min_contact_depth = 0.005; - - constraint_bias = 0.2; +GodotSpace2D::GodotSpace2D() { 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", Math::deg2rad(8.0)); 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::FLOAT, "physics/2d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); - broadphase = BroadPhase2DSW::create_func(); + broadphase = GodotBroadPhase2D::create_func(); broadphase->set_pair_callback(_broadphase_pair, this); broadphase->set_unpair_callback(_broadphase_unpair, this); - area = nullptr; - direct_access = memnew(PhysicsDirectSpaceState2DSW); + direct_access = memnew(GodotPhysicsDirectSpaceState2D); direct_access->space = this; - - for (int i = 0; i < ELAPSED_TIME_MAX; i++) { - elapsed_time[i] = 0; - } } -Space2DSW::~Space2DSW() { +GodotSpace2D::~GodotSpace2D() { memdelete(broadphase); memdelete(direct_access); } diff --git a/servers/physics_2d/godot_space_2d.h b/servers/physics_2d/godot_space_2d.h new file mode 100644 index 0000000000..b155a834b6 --- /dev/null +++ b/servers/physics_2d/godot_space_2d.h @@ -0,0 +1,209 @@ +/*************************************************************************/ +/* godot_space_2d.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef GODOT_SPACE_2D_H +#define GODOT_SPACE_2D_H + +#include "godot_area_2d.h" +#include "godot_area_pair_2d.h" +#include "godot_body_2d.h" +#include "godot_body_pair_2d.h" +#include "godot_broad_phase_2d.h" +#include "godot_collision_object_2d.h" + +#include "core/config/project_settings.h" +#include "core/templates/hash_map.h" +#include "core/typedefs.h" + +class GodotPhysicsDirectSpaceState2D : public PhysicsDirectSpaceState2D { + GDCLASS(GodotPhysicsDirectSpaceState2D, PhysicsDirectSpaceState2D); + +public: + GodotSpace2D *space = nullptr; + + virtual int intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) override; + virtual bool intersect_ray(const RayParameters &p_parameters, RayResult &r_result) override; + virtual int intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) override; + virtual bool cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe) override; + virtual bool collide_shape(const ShapeParameters &p_parameters, Vector2 *r_results, int p_result_max, int &r_result_count) override; + virtual bool rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) override; + + GodotPhysicsDirectSpaceState2D() {} +}; + +class GodotSpace2D { +public: + enum ElapsedTime { + ELAPSED_TIME_INTEGRATE_FORCES, + ELAPSED_TIME_GENERATE_ISLANDS, + ELAPSED_TIME_SETUP_CONSTRAINTS, + ELAPSED_TIME_SOLVE_CONSTRAINTS, + ELAPSED_TIME_INTEGRATE_VELOCITIES, + ELAPSED_TIME_MAX + + }; + +private: + struct ExcludedShapeSW { + GodotShape2D *local_shape = nullptr; + const GodotCollisionObject2D *against_object = nullptr; + int against_shape_index = 0; + }; + + uint64_t elapsed_time[ELAPSED_TIME_MAX] = {}; + + GodotPhysicsDirectSpaceState2D *direct_access = nullptr; + RID self; + + GodotBroadPhase2D *broadphase; + SelfList<GodotBody2D>::List active_list; + SelfList<GodotBody2D>::List mass_properties_update_list; + SelfList<GodotBody2D>::List state_query_list; + SelfList<GodotArea2D>::List monitor_query_list; + SelfList<GodotArea2D>::List area_moved_list; + + static void *_broadphase_pair(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_self); + static void _broadphase_unpair(GodotCollisionObject2D *A, int p_subindex_A, GodotCollisionObject2D *B, int p_subindex_B, void *p_data, void *p_self); + + Set<GodotCollisionObject2D *> objects; + + GodotArea2D *area = nullptr; + + real_t contact_recycle_radius = 1.0; + real_t contact_max_separation = 1.5; + real_t contact_max_allowed_penetration = 0.3; + real_t constraint_bias = 0.2; + + enum { + INTERSECTION_QUERY_MAX = 2048 + }; + + GodotCollisionObject2D *intersection_query_results[INTERSECTION_QUERY_MAX]; + int intersection_query_subindex_results[INTERSECTION_QUERY_MAX]; + + real_t body_linear_velocity_sleep_threshold = 0.0; + real_t body_angular_velocity_sleep_threshold = 0.0; + real_t body_time_to_sleep = 0.0; + + bool locked = false; + + real_t last_step = 0.001; + + int island_count = 0; + int active_objects = 0; + int collision_pairs = 0; + + int _cull_aabb_for_body(GodotBody2D *p_body, const Rect2 &p_aabb); + + Vector<Vector2> contact_debug; + int contact_debug_count = 0; + + friend class GodotPhysicsDirectSpaceState2D; + +public: + _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; } + _FORCE_INLINE_ RID get_self() const { return self; } + + void set_default_area(GodotArea2D *p_area) { area = p_area; } + GodotArea2D *get_default_area() const { return area; } + + const SelfList<GodotBody2D>::List &get_active_body_list() const; + void body_add_to_active_list(SelfList<GodotBody2D> *p_body); + void body_remove_from_active_list(SelfList<GodotBody2D> *p_body); + void body_add_to_mass_properties_update_list(SelfList<GodotBody2D> *p_body); + void body_remove_from_mass_properties_update_list(SelfList<GodotBody2D> *p_body); + void area_add_to_moved_list(SelfList<GodotArea2D> *p_area); + void area_remove_from_moved_list(SelfList<GodotArea2D> *p_area); + const SelfList<GodotArea2D>::List &get_moved_area_list() const; + + void body_add_to_state_query_list(SelfList<GodotBody2D> *p_body); + void body_remove_from_state_query_list(SelfList<GodotBody2D> *p_body); + + void area_add_to_monitor_query_list(SelfList<GodotArea2D> *p_area); + void area_remove_from_monitor_query_list(SelfList<GodotArea2D> *p_area); + + GodotBroadPhase2D *get_broadphase(); + + void add_object(GodotCollisionObject2D *p_object); + void remove_object(GodotCollisionObject2D *p_object); + const Set<GodotCollisionObject2D *> &get_objects() const; + + _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; } + _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; } + _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; } + _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; } + _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_threshold() const { return body_linear_velocity_sleep_threshold; } + _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_threshold() const { return body_angular_velocity_sleep_threshold; } + _FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; } + + void update(); + void setup(); + void call_queries(); + + bool is_locked() const; + void lock(); + void unlock(); + + real_t get_last_step() const { return last_step; } + void set_last_step(real_t p_step) { last_step = p_step; } + + void set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value); + real_t get_param(PhysicsServer2D::SpaceParameter p_param) const; + + void set_island_count(int p_island_count) { island_count = p_island_count; } + int get_island_count() const { return island_count; } + + void set_active_objects(int p_active_objects) { active_objects = p_active_objects; } + int get_active_objects() const { return active_objects; } + + int get_collision_pairs() const { return collision_pairs; } + + bool test_body_motion(GodotBody2D *p_body, const PhysicsServer2D::MotionParameters &p_parameters, PhysicsServer2D::MotionResult *r_result); + + void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } + _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); } + _FORCE_INLINE_ void add_debug_contact(const Vector2 &p_contact) { + if (contact_debug_count < contact_debug.size()) { + contact_debug.write[contact_debug_count++] = p_contact; + } + } + _FORCE_INLINE_ Vector<Vector2> get_debug_contacts() { return contact_debug; } + _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; } + + GodotPhysicsDirectSpaceState2D *get_direct_state(); + + void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; } + uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; } + + GodotSpace2D(); + ~GodotSpace2D(); +}; + +#endif // GODOT_SPACE_2D_H diff --git a/servers/physics_2d/step_2d_sw.cpp b/servers/physics_2d/godot_step_2d.cpp index 0306ec5050..00d11acdab 100644 --- a/servers/physics_2d/step_2d_sw.cpp +++ b/servers/physics_2d/godot_step_2d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* step_2d_sw.cpp */ +/* godot_step_2d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,7 +28,7 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "step_2d_sw.h" +#include "godot_step_2d.h" #include "core/os/os.h" @@ -38,7 +38,7 @@ #define ISLAND_SIZE_RESERVE 512 #define CONSTRAINT_COUNT_RESERVE 1024 -void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island) { +void GodotStep2D::_populate_island(GodotBody2D *p_body, LocalVector<GodotBody2D *> &p_body_island, LocalVector<GodotConstraint2D *> &p_constraint_island) { p_body->set_island_step(_step); if (p_body->get_mode() > PhysicsServer2D::BODY_MODE_KINEMATIC) { @@ -46,8 +46,8 @@ void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_bod p_body_island.push_back(p_body); } - for (const Pair<Constraint2DSW *, int> &E : p_body->get_constraint_list()) { - Constraint2DSW *constraint = (Constraint2DSW *)E.first; + for (const Pair<GodotConstraint2D *, int> &E : p_body->get_constraint_list()) { + GodotConstraint2D *constraint = (GodotConstraint2D *)E.first; if (constraint->get_island_step() == _step) { continue; // Already processed. } @@ -59,7 +59,7 @@ void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_bod if (i == E.second) { continue; } - Body2DSW *other_body = constraint->get_body_ptr()[i]; + GodotBody2D *other_body = constraint->get_body_ptr()[i]; if (other_body->get_island_step() == _step) { continue; // Already processed. } @@ -71,16 +71,16 @@ void Step2DSW::_populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_bod } } -void Step2DSW::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) { - Constraint2DSW *constraint = all_constraints[p_constraint_index]; +void GodotStep2D::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) { + GodotConstraint2D *constraint = all_constraints[p_constraint_index]; constraint->setup(delta); } -void Step2DSW::_pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island) const { +void GodotStep2D::_pre_solve_island(LocalVector<GodotConstraint2D *> &p_constraint_island) const { uint32_t constraint_count = p_constraint_island.size(); uint32_t valid_constraint_count = 0; for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) { - Constraint2DSW *constraint = p_constraint_island[constraint_index]; + GodotConstraint2D *constraint = p_constraint_island[constraint_index]; if (p_constraint_island[constraint_index]->pre_solve(delta)) { // Keep this constraint for solving. p_constraint_island[valid_constraint_count++] = constraint; @@ -89,8 +89,8 @@ void Step2DSW::_pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_isl p_constraint_island.resize(valid_constraint_count); } -void Step2DSW::_solve_island(uint32_t p_island_index, void *p_userdata) const { - const LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[p_island_index]; +void GodotStep2D::_solve_island(uint32_t p_island_index, void *p_userdata) const { + const LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[p_island_index]; for (int i = 0; i < iterations; i++) { uint32_t constraint_count = constraint_island.size(); @@ -100,12 +100,12 @@ void Step2DSW::_solve_island(uint32_t p_island_index, void *p_userdata) const { } } -void Step2DSW::_check_suspend(LocalVector<Body2DSW *> &p_body_island) const { +void GodotStep2D::_check_suspend(LocalVector<GodotBody2D *> &p_body_island) const { bool can_sleep = true; uint32_t body_count = p_body_island.size(); for (uint32_t body_index = 0; body_index < body_count; ++body_index) { - Body2DSW *body = p_body_island[body_index]; + GodotBody2D *body = p_body_island[body_index]; if (!body->sleep_test(delta)) { can_sleep = false; @@ -114,7 +114,7 @@ void Step2DSW::_check_suspend(LocalVector<Body2DSW *> &p_body_island) const { // Put all to sleep or wake up everyone. for (uint32_t body_index = 0; body_index < body_count; ++body_index) { - Body2DSW *body = p_body_island[body_index]; + GodotBody2D *body = p_body_island[body_index]; bool active = body->is_active(); @@ -124,7 +124,7 @@ void Step2DSW::_check_suspend(LocalVector<Body2DSW *> &p_body_island) const { } } -void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { +void GodotStep2D::step(GodotSpace2D *p_space, real_t p_delta, int p_iterations) { p_space->lock(); // can't access space during this p_space->setup(); //update inertias, etc @@ -134,7 +134,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { iterations = p_iterations; delta = p_delta; - const SelfList<Body2DSW>::List *body_list = &p_space->get_active_body_list(); + const SelfList<GodotBody2D>::List *body_list = &p_space->get_active_body_list(); /* INTEGRATE FORCES */ @@ -143,7 +143,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { int active_count = 0; - const SelfList<Body2DSW> *b = body_list->first(); + const SelfList<GodotBody2D> *b = body_list->first(); while (b) { b->self()->integrate_forces(p_delta); b = b->next(); @@ -152,9 +152,12 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { p_space->set_active_objects(active_count); + // Update the broadphase to register collision pairs. + p_space->update(); + { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } @@ -162,11 +165,11 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { uint32_t island_count = 0; - const SelfList<Area2DSW>::List &aml = p_space->get_moved_area_list(); + const SelfList<GodotArea2D>::List &aml = p_space->get_moved_area_list(); while (aml.first()) { - for (const Set<Constraint2DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) { - Constraint2DSW *constraint = E->get(); + for (const Set<GodotConstraint2D *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) { + GodotConstraint2D *constraint = E->get(); if (constraint->get_island_step() == _step) { continue; } @@ -177,13 +180,13 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { if (constraint_islands.size() < island_count) { constraint_islands.resize(island_count); } - LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1]; + LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[island_count - 1]; constraint_island.clear(); all_constraints.push_back(constraint); constraint_island.push_back(constraint); } - p_space->area_remove_from_moved_list((SelfList<Area2DSW> *)aml.first()); //faster to remove here + p_space->area_remove_from_moved_list((SelfList<GodotArea2D> *)aml.first()); //faster to remove here } /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */ @@ -193,14 +196,14 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { uint32_t body_island_count = 0; while (b) { - Body2DSW *body = b->self(); + GodotBody2D *body = b->self(); if (body->get_island_step() != _step) { ++body_island_count; if (body_islands.size() < body_island_count) { body_islands.resize(body_island_count); } - LocalVector<Body2DSW *> &body_island = body_islands[body_island_count - 1]; + LocalVector<GodotBody2D *> &body_island = body_islands[body_island_count - 1]; body_island.clear(); body_island.reserve(BODY_ISLAND_SIZE_RESERVE); @@ -208,7 +211,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { if (constraint_islands.size() < island_count) { constraint_islands.resize(island_count); } - LocalVector<Constraint2DSW *> &constraint_island = constraint_islands[island_count - 1]; + LocalVector<GodotConstraint2D *> &constraint_island = constraint_islands[island_count - 1]; constraint_island.clear(); constraint_island.reserve(ISLAND_SIZE_RESERVE); @@ -229,18 +232,18 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } /* SETUP CONSTRAINTS / PROCESS COLLISIONS */ uint32_t total_contraint_count = all_constraints.size(); - work_pool.do_work(total_contraint_count, this, &Step2DSW::_setup_contraint, nullptr); + work_pool.do_work(total_contraint_count, this, &GodotStep2D::_setup_contraint, nullptr); { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } @@ -255,15 +258,11 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { // Warning: _solve_island modifies the constraint islands for optimization purpose, // their content is not reliable after these calls and shouldn't be used anymore. - if (island_count > 1) { - work_pool.do_work(island_count, this, &Step2DSW::_solve_island, nullptr); - } else if (island_count > 0) { - _solve_island(0); - } + work_pool.do_work(island_count, this, &GodotStep2D::_solve_island, nullptr); { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } @@ -271,7 +270,7 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { b = body_list->first(); while (b) { - const SelfList<Body2DSW> *n = b->next(); + const SelfList<GodotBody2D> *n = b->next(); b->self()->integrate_velocities(p_delta); b = n; // in case it shuts itself down } @@ -284,20 +283,17 @@ void Step2DSW::step(Space2DSW *p_space, real_t p_delta, int p_iterations) { { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space2DSW::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace2D::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime); //profile_begtime=profile_endtime; } all_constraints.clear(); - p_space->update(); p_space->unlock(); _step++; } -Step2DSW::Step2DSW() { - _step = 1; - +GodotStep2D::GodotStep2D() { body_islands.reserve(BODY_ISLAND_COUNT_RESERVE); constraint_islands.reserve(ISLAND_COUNT_RESERVE); all_constraints.reserve(CONSTRAINT_COUNT_RESERVE); @@ -305,6 +301,6 @@ Step2DSW::Step2DSW() { work_pool.init(); } -Step2DSW::~Step2DSW() { +GodotStep2D::~GodotStep2D() { work_pool.finish(); } diff --git a/servers/physics_2d/step_2d_sw.h b/servers/physics_2d/godot_step_2d.h index c51fd73a79..efec243632 100644 --- a/servers/physics_2d/step_2d_sw.h +++ b/servers/physics_2d/godot_step_2d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* step_2d_sw.h */ +/* godot_step_2d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,36 +28,36 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef STEP_2D_SW_H -#define STEP_2D_SW_H +#ifndef GODOT_STEP_2D_H +#define GODOT_STEP_2D_H -#include "space_2d_sw.h" +#include "godot_space_2d.h" #include "core/templates/local_vector.h" #include "core/templates/thread_work_pool.h" -class Step2DSW { - uint64_t _step; +class GodotStep2D { + uint64_t _step = 1; int iterations = 0; real_t delta = 0.0; ThreadWorkPool work_pool; - LocalVector<LocalVector<Body2DSW *>> body_islands; - LocalVector<LocalVector<Constraint2DSW *>> constraint_islands; - LocalVector<Constraint2DSW *> all_constraints; + LocalVector<LocalVector<GodotBody2D *>> body_islands; + LocalVector<LocalVector<GodotConstraint2D *>> constraint_islands; + LocalVector<GodotConstraint2D *> all_constraints; - void _populate_island(Body2DSW *p_body, LocalVector<Body2DSW *> &p_body_island, LocalVector<Constraint2DSW *> &p_constraint_island); + void _populate_island(GodotBody2D *p_body, LocalVector<GodotBody2D *> &p_body_island, LocalVector<GodotConstraint2D *> &p_constraint_island); void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr); - void _pre_solve_island(LocalVector<Constraint2DSW *> &p_constraint_island) const; + void _pre_solve_island(LocalVector<GodotConstraint2D *> &p_constraint_island) const; void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr) const; - void _check_suspend(LocalVector<Body2DSW *> &p_body_island) const; + void _check_suspend(LocalVector<GodotBody2D *> &p_body_island) const; public: - void step(Space2DSW *p_space, real_t p_delta, int p_iterations); - Step2DSW(); - ~Step2DSW(); + void step(GodotSpace2D *p_space, real_t p_delta, int p_iterations); + GodotStep2D(); + ~GodotStep2D(); }; -#endif // STEP_2D_SW_H +#endif // GODOT_STEP_2D_H diff --git a/servers/physics_2d/physics_server_2d_sw.cpp b/servers/physics_2d/physics_server_2d_sw.cpp deleted file mode 100644 index 85b5e40752..0000000000 --- a/servers/physics_2d/physics_server_2d_sw.cpp +++ /dev/null @@ -1,1359 +0,0 @@ -/*************************************************************************/ -/* physics_server_2d_sw.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "physics_server_2d_sw.h" - -#include "body_direct_state_2d_sw.h" -#include "broad_phase_2d_bvh.h" -#include "collision_solver_2d_sw.h" -#include "core/config/project_settings.h" -#include "core/debugger/engine_debugger.h" -#include "core/os/os.h" - -#define FLUSH_QUERY_CHECK(m_object) \ - ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead."); - -RID PhysicsServer2DSW::_shape_create(ShapeType p_shape) { - Shape2DSW *shape = nullptr; - switch (p_shape) { - case SHAPE_WORLD_MARGIN: { - shape = memnew(WorldMarginShape2DSW); - } break; - case SHAPE_SEPARATION_RAY: { - shape = memnew(SeparationRayShape2DSW); - } break; - case SHAPE_SEGMENT: { - shape = memnew(SegmentShape2DSW); - } break; - case SHAPE_CIRCLE: { - shape = memnew(CircleShape2DSW); - } break; - case SHAPE_RECTANGLE: { - shape = memnew(RectangleShape2DSW); - } break; - case SHAPE_CAPSULE: { - shape = memnew(CapsuleShape2DSW); - } break; - case SHAPE_CONVEX_POLYGON: { - shape = memnew(ConvexPolygonShape2DSW); - } break; - case SHAPE_CONCAVE_POLYGON: { - shape = memnew(ConcavePolygonShape2DSW); - } break; - case SHAPE_CUSTOM: { - ERR_FAIL_V(RID()); - - } break; - } - - RID id = shape_owner.make_rid(shape); - shape->set_self(id); - - return id; -} - -RID PhysicsServer2DSW::world_margin_shape_create() { - return _shape_create(SHAPE_WORLD_MARGIN); -} - -RID PhysicsServer2DSW::separation_ray_shape_create() { - return _shape_create(SHAPE_SEPARATION_RAY); -} - -RID PhysicsServer2DSW::segment_shape_create() { - return _shape_create(SHAPE_SEGMENT); -} - -RID PhysicsServer2DSW::circle_shape_create() { - return _shape_create(SHAPE_CIRCLE); -} - -RID PhysicsServer2DSW::rectangle_shape_create() { - return _shape_create(SHAPE_RECTANGLE); -} - -RID PhysicsServer2DSW::capsule_shape_create() { - return _shape_create(SHAPE_CAPSULE); -} - -RID PhysicsServer2DSW::convex_polygon_shape_create() { - return _shape_create(SHAPE_CONVEX_POLYGON); -} - -RID PhysicsServer2DSW::concave_polygon_shape_create() { - return _shape_create(SHAPE_CONCAVE_POLYGON); -} - -void PhysicsServer2DSW::shape_set_data(RID p_shape, const Variant &p_data) { - Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - shape->set_data(p_data); -}; - -void PhysicsServer2DSW::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) { - Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - shape->set_custom_bias(p_bias); -} - -PhysicsServer2D::ShapeType PhysicsServer2DSW::shape_get_type(RID p_shape) const { - const Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM); - return shape->get_type(); -}; - -Variant PhysicsServer2DSW::shape_get_data(RID p_shape) const { - const Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND_V(!shape, Variant()); - ERR_FAIL_COND_V(!shape->is_configured(), Variant()); - return shape->get_data(); -}; - -real_t PhysicsServer2DSW::shape_get_custom_solver_bias(RID p_shape) const { - const Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND_V(!shape, 0); - return shape->get_custom_bias(); -} - -void PhysicsServer2DSW::_shape_col_cbk(const Vector2 &p_point_A, const Vector2 &p_point_B, void *p_userdata) { - CollCbkData *cbk = (CollCbkData *)p_userdata; - - if (cbk->max == 0) { - return; - } - - Vector2 rel_dir = (p_point_A - p_point_B); - real_t rel_length2 = rel_dir.length_squared(); - if (cbk->valid_dir != Vector2()) { - if (cbk->valid_depth < 10e20) { - if (rel_length2 > cbk->valid_depth * cbk->valid_depth || - (rel_length2 > CMP_EPSILON && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON)) { - cbk->invalid_by_dir++; - return; - } - } else { - if (rel_length2 > 0 && cbk->valid_dir.dot(rel_dir.normalized()) < CMP_EPSILON) { - return; - } - } - } - - if (cbk->amount == cbk->max) { - //find least deep - real_t min_depth = 1e20; - int min_depth_idx = 0; - for (int i = 0; i < cbk->amount; i++) { - real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]); - if (d < min_depth) { - min_depth = d; - min_depth_idx = i; - } - } - - if (rel_length2 < min_depth) { - return; - } - cbk->ptr[min_depth_idx * 2 + 0] = p_point_A; - cbk->ptr[min_depth_idx * 2 + 1] = p_point_B; - cbk->passed++; - - } else { - cbk->ptr[cbk->amount * 2 + 0] = p_point_A; - cbk->ptr[cbk->amount * 2 + 1] = p_point_B; - cbk->amount++; - cbk->passed++; - } -} - -bool PhysicsServer2DSW::shape_collide(RID p_shape_A, const Transform2D &p_xform_A, const Vector2 &p_motion_A, RID p_shape_B, const Transform2D &p_xform_B, const Vector2 &p_motion_B, Vector2 *r_results, int p_result_max, int &r_result_count) { - Shape2DSW *shape_A = shape_owner.getornull(p_shape_A); - ERR_FAIL_COND_V(!shape_A, false); - Shape2DSW *shape_B = shape_owner.getornull(p_shape_B); - ERR_FAIL_COND_V(!shape_B, false); - - if (p_result_max == 0) { - return CollisionSolver2DSW::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, nullptr, nullptr); - } - - CollCbkData cbk; - cbk.max = p_result_max; - cbk.amount = 0; - cbk.passed = 0; - cbk.ptr = r_results; - - bool res = CollisionSolver2DSW::solve(shape_A, p_xform_A, p_motion_A, shape_B, p_xform_B, p_motion_B, _shape_col_cbk, &cbk); - r_result_count = cbk.amount; - return res; -} - -RID PhysicsServer2DSW::space_create() { - Space2DSW *space = memnew(Space2DSW); - RID id = space_owner.make_rid(space); - space->set_self(id); - RID area_id = area_create(); - Area2DSW *area = area_owner.getornull(area_id); - ERR_FAIL_COND_V(!area, RID()); - space->set_default_area(area); - area->set_space(space); - area->set_priority(-1); - - return id; -}; - -void PhysicsServer2DSW::space_set_active(RID p_space, bool p_active) { - Space2DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - if (p_active) { - active_spaces.insert(space); - } else { - active_spaces.erase(space); - } -} - -bool PhysicsServer2DSW::space_is_active(RID p_space) const { - const Space2DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, false); - - return active_spaces.has(space); -} - -void PhysicsServer2DSW::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { - Space2DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - - space->set_param(p_param, p_value); -} - -real_t PhysicsServer2DSW::space_get_param(RID p_space, SpaceParameter p_param) const { - const Space2DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, 0); - return space->get_param(p_param); -} - -void PhysicsServer2DSW::space_set_debug_contacts(RID p_space, int p_max_contacts) { - Space2DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - space->set_debug_contacts(p_max_contacts); -} - -Vector<Vector2> PhysicsServer2DSW::space_get_contacts(RID p_space) const { - Space2DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, Vector<Vector2>()); - return space->get_debug_contacts(); -} - -int PhysicsServer2DSW::space_get_contact_count(RID p_space) const { - Space2DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, 0); - return space->get_debug_contact_count(); -} - -PhysicsDirectSpaceState2D *PhysicsServer2DSW::space_get_direct_state(RID p_space) { - Space2DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, nullptr); - ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification."); - - return space->get_direct_state(); -} - -RID PhysicsServer2DSW::area_create() { - Area2DSW *area = memnew(Area2DSW); - RID rid = area_owner.make_rid(area); - area->set_self(rid); - return rid; -}; - -void PhysicsServer2DSW::area_set_space(RID p_area, RID p_space) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - Space2DSW *space = nullptr; - if (p_space.is_valid()) { - space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - } - - if (area->get_space() == space) { - return; //pointless - } - - area->clear_constraints(); - area->set_space(space); -}; - -RID PhysicsServer2DSW::area_get_space(RID p_area) const { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, RID()); - - Space2DSW *space = area->get_space(); - if (!space) { - return RID(); - } - return space->get_self(); -}; - -void PhysicsServer2DSW::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_space_override_mode(p_mode); -} - -PhysicsServer2D::AreaSpaceOverrideMode PhysicsServer2DSW::area_get_space_override_mode(RID p_area) const { - const Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, AREA_SPACE_OVERRIDE_DISABLED); - - return area->get_space_override_mode(); -} - -void PhysicsServer2DSW::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - - area->add_shape(shape, p_transform, p_disabled); -} - -void PhysicsServer2DSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - ERR_FAIL_COND(!shape->is_configured()); - - area->set_shape(p_shape_idx, shape); -} - -void PhysicsServer2DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_shape_transform(p_shape_idx, p_transform); -} - -void PhysicsServer2DSW::area_set_shape_disabled(RID p_area, int p_shape, bool p_disabled) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - ERR_FAIL_INDEX(p_shape, area->get_shape_count()); - FLUSH_QUERY_CHECK(area); - - area->set_shape_disabled(p_shape, p_disabled); -} - -int PhysicsServer2DSW::area_get_shape_count(RID p_area) const { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, -1); - - return area->get_shape_count(); -} - -RID PhysicsServer2DSW::area_get_shape(RID p_area, int p_shape_idx) const { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, RID()); - - Shape2DSW *shape = area->get_shape(p_shape_idx); - ERR_FAIL_COND_V(!shape, RID()); - - return shape->get_self(); -} - -Transform2D PhysicsServer2DSW::area_get_shape_transform(RID p_area, int p_shape_idx) const { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform2D()); - - return area->get_shape_transform(p_shape_idx); -} - -void PhysicsServer2DSW::area_remove_shape(RID p_area, int p_shape_idx) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->remove_shape(p_shape_idx); -} - -void PhysicsServer2DSW::area_clear_shapes(RID p_area) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - while (area->get_shape_count()) { - area->remove_shape(0); - } -} - -void PhysicsServer2DSW::area_attach_object_instance_id(RID p_area, ObjectID p_id) { - if (space_owner.owns(p_area)) { - Space2DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - area->set_instance_id(p_id); -} - -ObjectID PhysicsServer2DSW::area_get_object_instance_id(RID p_area) const { - if (space_owner.owns(p_area)) { - Space2DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, ObjectID()); - return area->get_instance_id(); -} - -void PhysicsServer2DSW::area_attach_canvas_instance_id(RID p_area, ObjectID p_id) { - if (space_owner.owns(p_area)) { - Space2DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - area->set_canvas_instance_id(p_id); -} - -ObjectID PhysicsServer2DSW::area_get_canvas_instance_id(RID p_area) const { - if (space_owner.owns(p_area)) { - Space2DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, ObjectID()); - return area->get_canvas_instance_id(); -} - -void PhysicsServer2DSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) { - if (space_owner.owns(p_area)) { - Space2DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - area->set_param(p_param, p_value); -}; - -void PhysicsServer2DSW::area_set_transform(RID p_area, const Transform2D &p_transform) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - area->set_transform(p_transform); -}; - -Variant PhysicsServer2DSW::area_get_param(RID p_area, AreaParameter p_param) const { - if (space_owner.owns(p_area)) { - Space2DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Variant()); - - return area->get_param(p_param); -}; - -Transform2D PhysicsServer2DSW::area_get_transform(RID p_area) const { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform2D()); - - return area->get_transform(); -}; - -void PhysicsServer2DSW::area_set_pickable(RID p_area, bool p_pickable) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - area->set_pickable(p_pickable); -} - -void PhysicsServer2DSW::area_set_monitorable(RID p_area, bool p_monitorable) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - FLUSH_QUERY_CHECK(area); - - area->set_monitorable(p_monitorable); -} - -void PhysicsServer2DSW::area_set_collision_mask(RID p_area, uint32_t p_mask) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_collision_mask(p_mask); -} - -void PhysicsServer2DSW::area_set_collision_layer(RID p_area, uint32_t p_layer) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_collision_layer(p_layer); -} - -void PhysicsServer2DSW::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method); -} - -void PhysicsServer2DSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { - Area2DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method); -} - -/* BODY API */ - -RID PhysicsServer2DSW::body_create() { - Body2DSW *body = memnew(Body2DSW); - RID rid = body_owner.make_rid(body); - body->set_self(rid); - return rid; -} - -void PhysicsServer2DSW::body_set_space(RID p_body, RID p_space) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - Space2DSW *space = nullptr; - if (p_space.is_valid()) { - space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - } - - if (body->get_space() == space) { - return; //pointless - } - - body->clear_constraint_list(); - body->set_space(space); -}; - -RID PhysicsServer2DSW::body_get_space(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, RID()); - - Space2DSW *space = body->get_space(); - if (!space) { - return RID(); - } - return space->get_self(); -}; - -void PhysicsServer2DSW::body_set_mode(RID p_body, BodyMode p_mode) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - FLUSH_QUERY_CHECK(body); - - body->set_mode(p_mode); -}; - -PhysicsServer2D::BodyMode PhysicsServer2DSW::body_get_mode(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, BODY_MODE_STATIC); - - return body->get_mode(); -}; - -void PhysicsServer2DSW::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - - body->add_shape(shape, p_transform, p_disabled); -} - -void PhysicsServer2DSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - Shape2DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - ERR_FAIL_COND(!shape->is_configured()); - - body->set_shape(p_shape_idx, shape); -} - -void PhysicsServer2DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_shape_transform(p_shape_idx, p_transform); -} - -void PhysicsServer2DSW::body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_shape_metadata(p_shape_idx, p_metadata); -} - -Variant PhysicsServer2DSW::body_get_shape_metadata(RID p_body, int p_shape_idx) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Variant()); - return body->get_shape_metadata(p_shape_idx); -} - -int PhysicsServer2DSW::body_get_shape_count(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, -1); - - return body->get_shape_count(); -} - -RID PhysicsServer2DSW::body_get_shape(RID p_body, int p_shape_idx) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, RID()); - - Shape2DSW *shape = body->get_shape(p_shape_idx); - ERR_FAIL_COND_V(!shape, RID()); - - return shape->get_self(); -} - -Transform2D PhysicsServer2DSW::body_get_shape_transform(RID p_body, int p_shape_idx) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Transform2D()); - - return body->get_shape_transform(p_shape_idx); -} - -void PhysicsServer2DSW::body_remove_shape(RID p_body, int p_shape_idx) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->remove_shape(p_shape_idx); -} - -void PhysicsServer2DSW::body_clear_shapes(RID p_body) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - while (body->get_shape_count()) { - body->remove_shape(0); - } -} - -void PhysicsServer2DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); - FLUSH_QUERY_CHECK(body); - - body->set_shape_disabled(p_shape_idx, p_disabled); -} - -void PhysicsServer2DSW::body_set_shape_as_one_way_collision(RID p_body, int p_shape_idx, bool p_enable, real_t p_margin) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); - FLUSH_QUERY_CHECK(body); - - body->set_shape_as_one_way_collision(p_shape_idx, p_enable, p_margin); -} - -void PhysicsServer2DSW::body_set_continuous_collision_detection_mode(RID p_body, CCDMode p_mode) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_continuous_collision_detection_mode(p_mode); -} - -PhysicsServer2DSW::CCDMode PhysicsServer2DSW::body_get_continuous_collision_detection_mode(RID p_body) const { - const Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, CCD_MODE_DISABLED); - - return body->get_continuous_collision_detection_mode(); -} - -void PhysicsServer2DSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_instance_id(p_id); -}; - -ObjectID PhysicsServer2DSW::body_get_object_instance_id(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, ObjectID()); - - return body->get_instance_id(); -}; - -void PhysicsServer2DSW::body_attach_canvas_instance_id(RID p_body, ObjectID p_id) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_canvas_instance_id(p_id); -}; - -ObjectID PhysicsServer2DSW::body_get_canvas_instance_id(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, ObjectID()); - - return body->get_canvas_instance_id(); -}; - -void PhysicsServer2DSW::body_set_collision_layer(RID p_body, uint32_t p_layer) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_collision_layer(p_layer); -}; - -uint32_t PhysicsServer2DSW::body_get_collision_layer(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_collision_layer(); -}; - -void PhysicsServer2DSW::body_set_collision_mask(RID p_body, uint32_t p_mask) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_collision_mask(p_mask); -}; - -uint32_t PhysicsServer2DSW::body_get_collision_mask(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_collision_mask(); -}; - -void PhysicsServer2DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_param(p_param, p_value); -}; - -real_t PhysicsServer2DSW::body_get_param(RID p_body, BodyParameter p_param) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_param(p_param); -}; - -void PhysicsServer2DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_state(p_state, p_variant); -}; - -Variant PhysicsServer2DSW::body_get_state(RID p_body, BodyState p_state) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Variant()); - - return body->get_state(p_state); -}; - -void PhysicsServer2DSW::body_set_applied_force(RID p_body, const Vector2 &p_force) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_applied_force(p_force); - body->wakeup(); -}; - -Vector2 PhysicsServer2DSW::body_get_applied_force(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Vector2()); - return body->get_applied_force(); -}; - -void PhysicsServer2DSW::body_set_applied_torque(RID p_body, real_t p_torque) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_applied_torque(p_torque); - body->wakeup(); -}; - -real_t PhysicsServer2DSW::body_get_applied_torque(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_applied_torque(); -}; - -void PhysicsServer2DSW::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->apply_central_impulse(p_impulse); - body->wakeup(); -} - -void PhysicsServer2DSW::body_apply_torque_impulse(RID p_body, real_t p_torque) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - _update_shapes(); - - body->apply_torque_impulse(p_torque); - body->wakeup(); -} - -void PhysicsServer2DSW::body_apply_impulse(RID p_body, const Vector2 &p_impulse, const Vector2 &p_position) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - _update_shapes(); - - body->apply_impulse(p_impulse, p_position); - body->wakeup(); -}; - -void PhysicsServer2DSW::body_add_central_force(RID p_body, const Vector2 &p_force) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->add_central_force(p_force); - body->wakeup(); -}; - -void PhysicsServer2DSW::body_add_force(RID p_body, const Vector2 &p_force, const Vector2 &p_position) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->add_force(p_force, p_position); - body->wakeup(); -}; - -void PhysicsServer2DSW::body_add_torque(RID p_body, real_t p_torque) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->add_torque(p_torque); - body->wakeup(); -}; - -void PhysicsServer2DSW::body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - _update_shapes(); - - Vector2 v = body->get_linear_velocity(); - Vector2 axis = p_axis_velocity.normalized(); - v -= axis * axis.dot(v); - v += p_axis_velocity; - body->set_linear_velocity(v); - body->wakeup(); -}; - -void PhysicsServer2DSW::body_add_collision_exception(RID p_body, RID p_body_b) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->add_exception(p_body_b); - body->wakeup(); -}; - -void PhysicsServer2DSW::body_remove_collision_exception(RID p_body, RID p_body_b) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->remove_exception(p_body_b); - body->wakeup(); -}; - -void PhysicsServer2DSW::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - for (int i = 0; i < body->get_exceptions().size(); i++) { - p_exceptions->push_back(body->get_exceptions()[i]); - } -}; - -void PhysicsServer2DSW::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); -}; - -real_t PhysicsServer2DSW::body_get_contacts_reported_depth_threshold(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - return 0; -}; - -void PhysicsServer2DSW::body_set_omit_force_integration(RID p_body, bool p_omit) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_omit_force_integration(p_omit); -}; - -bool PhysicsServer2DSW::body_is_omitting_force_integration(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, false); - return body->get_omit_force_integration(); -}; - -void PhysicsServer2DSW::body_set_max_contacts_reported(RID p_body, int p_contacts) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_max_contacts_reported(p_contacts); -} - -int PhysicsServer2DSW::body_get_max_contacts_reported(RID p_body) const { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, -1); - return body->get_max_contacts_reported(); -} - -void PhysicsServer2DSW::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_state_sync_callback(p_instance, p_callback); -} - -void PhysicsServer2DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_force_integration_callback(p_callable, p_udata); -} - -bool PhysicsServer2DSW::body_collide_shape(RID p_body, int p_body_shape, RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, Vector2 *r_results, int p_result_max, int &r_result_count) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, false); - ERR_FAIL_INDEX_V(p_body_shape, body->get_shape_count(), false); - - return shape_collide(body->get_shape(p_body_shape)->get_self(), body->get_transform() * body->get_shape_transform(p_body_shape), Vector2(), p_shape, p_shape_xform, p_motion, r_results, p_result_max, r_result_count); -} - -void PhysicsServer2DSW::body_set_pickable(RID p_body, bool p_pickable) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_pickable(p_pickable); -} - -bool PhysicsServer2DSW::body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, MotionResult *r_result, bool p_collide_separation_ray, const Set<RID> &p_exclude) { - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, false); - ERR_FAIL_COND_V(!body->get_space(), false); - ERR_FAIL_COND_V(body->get_space()->is_locked(), false); - - _update_shapes(); - - return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result, p_collide_separation_ray, p_exclude); -} - -PhysicsDirectBodyState2D *PhysicsServer2DSW::body_get_direct_state(RID p_body) { - ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); - - Body2DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, nullptr); - - ERR_FAIL_COND_V(!body->get_space(), nullptr); - ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); - - return body->get_direct_state(); -} - -/* JOINT API */ - -RID PhysicsServer2DSW::joint_create() { - Joint2DSW *joint = memnew(Joint2DSW); - RID joint_rid = joint_owner.make_rid(joint); - joint->set_self(joint_rid); - return joint_rid; -} - -void PhysicsServer2DSW::joint_clear(RID p_joint) { - Joint2DSW *joint = joint_owner.getornull(p_joint); - if (joint->get_type() != JOINT_TYPE_MAX) { - Joint2DSW *empty_joint = memnew(Joint2DSW); - empty_joint->copy_settings_from(joint); - - joint_owner.replace(p_joint, empty_joint); - memdelete(joint); - } -} - -void PhysicsServer2DSW::joint_set_param(RID p_joint, JointParam p_param, real_t p_value) { - Joint2DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - - switch (p_param) { - case JOINT_PARAM_BIAS: - joint->set_bias(p_value); - break; - case JOINT_PARAM_MAX_BIAS: - joint->set_max_bias(p_value); - break; - case JOINT_PARAM_MAX_FORCE: - joint->set_max_force(p_value); - break; - } -} - -real_t PhysicsServer2DSW::joint_get_param(RID p_joint, JointParam p_param) const { - const Joint2DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, -1); - - switch (p_param) { - case JOINT_PARAM_BIAS: - return joint->get_bias(); - break; - case JOINT_PARAM_MAX_BIAS: - return joint->get_max_bias(); - break; - case JOINT_PARAM_MAX_FORCE: - return joint->get_max_force(); - break; - } - - return 0; -} - -void PhysicsServer2DSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { - Joint2DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - - joint->disable_collisions_between_bodies(p_disable); - - if (2 == joint->get_body_count()) { - Body2DSW *body_a = *joint->get_body_ptr(); - Body2DSW *body_b = *(joint->get_body_ptr() + 1); - - if (p_disable) { - body_add_collision_exception(body_a->get_self(), body_b->get_self()); - body_add_collision_exception(body_b->get_self(), body_a->get_self()); - } else { - body_remove_collision_exception(body_a->get_self(), body_b->get_self()); - body_remove_collision_exception(body_b->get_self(), body_a->get_self()); - } - } -} - -bool PhysicsServer2DSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const { - const Joint2DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, true); - - return joint->is_disabled_collisions_between_bodies(); -} - -void PhysicsServer2DSW::joint_make_pin(RID p_joint, const Vector2 &p_pos, RID p_body_a, RID p_body_b) { - Body2DSW *A = body_owner.getornull(p_body_a); - ERR_FAIL_COND(!A); - Body2DSW *B = nullptr; - if (body_owner.owns(p_body_b)) { - B = body_owner.getornull(p_body_b); - ERR_FAIL_COND(!B); - } - - Joint2DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint2DSW *joint = memnew(PinJoint2DSW(p_pos, A, B)); - - joint_owner.replace(p_joint, joint); - joint->copy_settings_from(prev_joint); - memdelete(prev_joint); -} - -void PhysicsServer2DSW::joint_make_groove(RID p_joint, const Vector2 &p_a_groove1, const Vector2 &p_a_groove2, const Vector2 &p_b_anchor, RID p_body_a, RID p_body_b) { - Body2DSW *A = body_owner.getornull(p_body_a); - ERR_FAIL_COND(!A); - - Body2DSW *B = body_owner.getornull(p_body_b); - ERR_FAIL_COND(!B); - - Joint2DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint2DSW *joint = memnew(GrooveJoint2DSW(p_a_groove1, p_a_groove2, p_b_anchor, A, B)); - - joint_owner.replace(p_joint, joint); - joint->copy_settings_from(prev_joint); - memdelete(prev_joint); -} - -void PhysicsServer2DSW::joint_make_damped_spring(RID p_joint, const Vector2 &p_anchor_a, const Vector2 &p_anchor_b, RID p_body_a, RID p_body_b) { - Body2DSW *A = body_owner.getornull(p_body_a); - ERR_FAIL_COND(!A); - - Body2DSW *B = body_owner.getornull(p_body_b); - ERR_FAIL_COND(!B); - - Joint2DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint2DSW *joint = memnew(DampedSpringJoint2DSW(p_anchor_a, p_anchor_b, A, B)); - - joint_owner.replace(p_joint, joint); - joint->copy_settings_from(prev_joint); - memdelete(prev_joint); -} - -void PhysicsServer2DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { - Joint2DSW *j = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!j); - ERR_FAIL_COND(j->get_type() != JOINT_TYPE_PIN); - - PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j); - pin_joint->set_param(p_param, p_value); -} - -real_t PhysicsServer2DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { - Joint2DSW *j = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!j, 0); - ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_PIN, 0); - - PinJoint2DSW *pin_joint = static_cast<PinJoint2DSW *>(j); - return pin_joint->get_param(p_param); -} - -void PhysicsServer2DSW::damped_spring_joint_set_param(RID p_joint, DampedSpringParam p_param, real_t p_value) { - Joint2DSW *j = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!j); - ERR_FAIL_COND(j->get_type() != JOINT_TYPE_DAMPED_SPRING); - - DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j); - dsj->set_param(p_param, p_value); -} - -real_t PhysicsServer2DSW::damped_spring_joint_get_param(RID p_joint, DampedSpringParam p_param) const { - Joint2DSW *j = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!j, 0); - ERR_FAIL_COND_V(j->get_type() != JOINT_TYPE_DAMPED_SPRING, 0); - - DampedSpringJoint2DSW *dsj = static_cast<DampedSpringJoint2DSW *>(j); - return dsj->get_param(p_param); -} - -PhysicsServer2D::JointType PhysicsServer2DSW::joint_get_type(RID p_joint) const { - Joint2DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN); - - return joint->get_type(); -} - -void PhysicsServer2DSW::free(RID p_rid) { - _update_shapes(); // just in case - - if (shape_owner.owns(p_rid)) { - Shape2DSW *shape = shape_owner.getornull(p_rid); - - while (shape->get_owners().size()) { - ShapeOwner2DSW *so = shape->get_owners().front()->key(); - so->remove_shape(shape); - } - - shape_owner.free(p_rid); - memdelete(shape); - } else if (body_owner.owns(p_rid)) { - Body2DSW *body = body_owner.getornull(p_rid); - - /* - if (body->get_state_query()) - _clear_query(body->get_state_query()); - - if (body->get_direct_state_query()) - _clear_query(body->get_direct_state_query()); - */ - - body_set_space(p_rid, RID()); - - while (body->get_shape_count()) { - body->remove_shape(0); - } - - body_owner.free(p_rid); - memdelete(body); - - } else if (area_owner.owns(p_rid)) { - Area2DSW *area = area_owner.getornull(p_rid); - - /* - if (area->get_monitor_query()) - _clear_query(area->get_monitor_query()); - */ - - area->set_space(nullptr); - - while (area->get_shape_count()) { - area->remove_shape(0); - } - - area_owner.free(p_rid); - memdelete(area); - } else if (space_owner.owns(p_rid)) { - Space2DSW *space = space_owner.getornull(p_rid); - - while (space->get_objects().size()) { - CollisionObject2DSW *co = (CollisionObject2DSW *)space->get_objects().front()->get(); - co->set_space(nullptr); - } - - active_spaces.erase(space); - free(space->get_default_area()->get_self()); - space_owner.free(p_rid); - memdelete(space); - } else if (joint_owner.owns(p_rid)) { - Joint2DSW *joint = joint_owner.getornull(p_rid); - - joint_owner.free(p_rid); - memdelete(joint); - - } else { - ERR_FAIL_MSG("Invalid ID."); - } -}; - -void PhysicsServer2DSW::set_active(bool p_active) { - active = p_active; -}; - -void PhysicsServer2DSW::set_collision_iterations(int p_iterations) { - iterations = p_iterations; -}; - -void PhysicsServer2DSW::init() { - doing_sync = false; - iterations = 8; // 8? - stepper = memnew(Step2DSW); -}; - -void PhysicsServer2DSW::step(real_t p_step) { - if (!active) { - return; - } - - _update_shapes(); - - island_count = 0; - active_objects = 0; - collision_pairs = 0; - for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) { - stepper->step((Space2DSW *)E->get(), p_step, iterations); - island_count += E->get()->get_island_count(); - active_objects += E->get()->get_active_objects(); - collision_pairs += E->get()->get_collision_pairs(); - } -}; - -void PhysicsServer2DSW::sync() { - doing_sync = true; -}; - -void PhysicsServer2DSW::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()) { - Space2DSW *space = (Space2DSW *)E->get(); - space->call_queries(); - } - - flushing_queries = false; - - if (EngineDebugger::is_profiling("servers")) { - uint64_t total_time[Space2DSW::ELAPSED_TIME_MAX]; - static const char *time_name[Space2DSW::ELAPSED_TIME_MAX] = { - "integrate_forces", - "generate_islands", - "setup_constraints", - "solve_constraints", - "integrate_velocities" - }; - - for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) { - total_time[i] = 0; - } - - for (Set<const Space2DSW *>::Element *E = active_spaces.front(); E; E = E->next()) { - for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) { - total_time[i] += E->get()->get_elapsed_time(Space2DSW::ElapsedTime(i)); - } - } - - Array values; - values.resize(Space2DSW::ELAPSED_TIME_MAX * 2); - for (int i = 0; i < Space2DSW::ELAPSED_TIME_MAX; i++) { - values[i * 2 + 0] = time_name[i]; - values[i * 2 + 1] = USEC_TO_SEC(total_time[i]); - } - values.push_back("flush_queries"); - values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg)); - - values.push_front("physics_2d"); - EngineDebugger::profiler_add_frame_data("servers", values); - } -} - -void PhysicsServer2DSW::end_sync() { - doing_sync = false; -} - -void PhysicsServer2DSW::finish() { - memdelete(stepper); -}; - -void PhysicsServer2DSW::_update_shapes() { - while (pending_shape_update_list.first()) { - pending_shape_update_list.first()->self()->_shape_changed(); - pending_shape_update_list.remove(pending_shape_update_list.first()); - } -} - -int PhysicsServer2DSW::get_process_info(ProcessInfo p_info) { - switch (p_info) { - case INFO_ACTIVE_OBJECTS: { - return active_objects; - } break; - case INFO_COLLISION_PAIRS: { - return collision_pairs; - } break; - case INFO_ISLAND_COUNT: { - return island_count; - } break; - } - - return 0; -} - -PhysicsServer2DSW *PhysicsServer2DSW::singletonsw = nullptr; - -PhysicsServer2DSW::PhysicsServer2DSW(bool p_using_threads) { - singletonsw = this; - BroadPhase2DSW::create_func = BroadPhase2DBVH::_create; - - active = true; - island_count = 0; - active_objects = 0; - collision_pairs = 0; - using_threads = p_using_threads; - flushing_queries = false; -}; diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h deleted file mode 100644 index 5de071a475..0000000000 --- a/servers/physics_2d/space_2d_sw.h +++ /dev/null @@ -1,212 +0,0 @@ -/*************************************************************************/ -/* space_2d_sw.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SPACE_2D_SW_H -#define SPACE_2D_SW_H - -#include "area_2d_sw.h" -#include "area_pair_2d_sw.h" -#include "body_2d_sw.h" -#include "body_pair_2d_sw.h" -#include "broad_phase_2d_sw.h" -#include "collision_object_2d_sw.h" -#include "core/config/project_settings.h" -#include "core/templates/hash_map.h" -#include "core/typedefs.h" - -class PhysicsDirectSpaceState2DSW : public PhysicsDirectSpaceState2D { - GDCLASS(PhysicsDirectSpaceState2DSW, PhysicsDirectSpaceState2D); - - 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 = ObjectID()); - -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) override; - 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) override; - 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) override; - 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) override; - 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) override; - virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, 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) override; - virtual bool 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 = Set<RID>(), uint32_t p_collision_mask = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) override; - - PhysicsDirectSpaceState2DSW(); -}; - -class Space2DSW { -public: - enum ElapsedTime { - ELAPSED_TIME_INTEGRATE_FORCES, - ELAPSED_TIME_GENERATE_ISLANDS, - ELAPSED_TIME_SETUP_CONSTRAINTS, - ELAPSED_TIME_SOLVE_CONSTRAINTS, - ELAPSED_TIME_INTEGRATE_VELOCITIES, - ELAPSED_TIME_MAX - - }; - -private: - struct ExcludedShapeSW { - Shape2DSW *local_shape; - const CollisionObject2DSW *against_object; - int against_shape_index; - }; - - uint64_t elapsed_time[ELAPSED_TIME_MAX]; - - PhysicsDirectSpaceState2DSW *direct_access; - RID self; - - BroadPhase2DSW *broadphase; - SelfList<Body2DSW>::List active_list; - SelfList<Body2DSW>::List inertia_update_list; - SelfList<Body2DSW>::List state_query_list; - SelfList<Area2DSW>::List monitor_query_list; - SelfList<Area2DSW>::List area_moved_list; - - static void *_broadphase_pair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_self); - static void _broadphase_unpair(CollisionObject2DSW *A, int p_subindex_A, CollisionObject2DSW *B, int p_subindex_B, void *p_data, void *p_self); - - Set<CollisionObject2DSW *> objects; - - Area2DSW *area; - - real_t contact_recycle_radius; - real_t contact_max_separation; - real_t contact_max_allowed_penetration; - real_t constraint_bias; - real_t test_motion_min_contact_depth; - - enum { - INTERSECTION_QUERY_MAX = 2048 - }; - - CollisionObject2DSW *intersection_query_results[INTERSECTION_QUERY_MAX]; - int intersection_query_subindex_results[INTERSECTION_QUERY_MAX]; - - real_t body_linear_velocity_sleep_threshold; - real_t body_angular_velocity_sleep_threshold; - real_t body_time_to_sleep; - - bool locked; - - real_t last_step = 0.001; - - int island_count; - int active_objects; - int collision_pairs; - - int _cull_aabb_for_body(Body2DSW *p_body, const Rect2 &p_aabb); - - Vector<Vector2> contact_debug; - int contact_debug_count; - - friend class PhysicsDirectSpaceState2DSW; - -public: - _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; } - _FORCE_INLINE_ RID get_self() const { return self; } - - void set_default_area(Area2DSW *p_area) { area = p_area; } - Area2DSW *get_default_area() const { return area; } - - const SelfList<Body2DSW>::List &get_active_body_list() const; - void body_add_to_active_list(SelfList<Body2DSW> *p_body); - void body_remove_from_active_list(SelfList<Body2DSW> *p_body); - void body_add_to_inertia_update_list(SelfList<Body2DSW> *p_body); - void body_remove_from_inertia_update_list(SelfList<Body2DSW> *p_body); - void area_add_to_moved_list(SelfList<Area2DSW> *p_area); - void area_remove_from_moved_list(SelfList<Area2DSW> *p_area); - const SelfList<Area2DSW>::List &get_moved_area_list() const; - - void body_add_to_state_query_list(SelfList<Body2DSW> *p_body); - void body_remove_from_state_query_list(SelfList<Body2DSW> *p_body); - - void area_add_to_monitor_query_list(SelfList<Area2DSW> *p_area); - void area_remove_from_monitor_query_list(SelfList<Area2DSW> *p_area); - - BroadPhase2DSW *get_broadphase(); - - void add_object(CollisionObject2DSW *p_object); - void remove_object(CollisionObject2DSW *p_object); - const Set<CollisionObject2DSW *> &get_objects() const; - - _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; } - _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; } - _FORCE_INLINE_ real_t get_contact_max_allowed_penetration() const { return contact_max_allowed_penetration; } - _FORCE_INLINE_ real_t get_constraint_bias() const { return constraint_bias; } - _FORCE_INLINE_ real_t get_body_linear_velocity_sleep_threshold() const { return body_linear_velocity_sleep_threshold; } - _FORCE_INLINE_ real_t get_body_angular_velocity_sleep_threshold() const { return body_angular_velocity_sleep_threshold; } - _FORCE_INLINE_ real_t get_body_time_to_sleep() const { return body_time_to_sleep; } - - void update(); - void setup(); - void call_queries(); - - bool is_locked() const; - void lock(); - void unlock(); - - real_t get_last_step() const { return last_step; } - void set_last_step(real_t p_step) { last_step = p_step; } - - void set_param(PhysicsServer2D::SpaceParameter p_param, real_t p_value); - real_t get_param(PhysicsServer2D::SpaceParameter p_param) const; - - void set_island_count(int p_island_count) { island_count = p_island_count; } - int get_island_count() const { return island_count; } - - void set_active_objects(int p_active_objects) { active_objects = p_active_objects; } - int get_active_objects() const { return active_objects; } - - int get_collision_pairs() const { return collision_pairs; } - - bool test_body_motion(Body2DSW *p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, PhysicsServer2D::MotionResult *r_result, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()); - - void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } - _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); } - _FORCE_INLINE_ void add_debug_contact(const Vector2 &p_contact) { - if (contact_debug_count < contact_debug.size()) { - contact_debug.write[contact_debug_count++] = p_contact; - } - } - _FORCE_INLINE_ Vector<Vector2> get_debug_contacts() { return contact_debug; } - _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; } - - PhysicsDirectSpaceState2DSW *get_direct_state(); - - void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; } - uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; } - - Space2DSW(); - ~Space2DSW(); -}; - -#endif // SPACE_2D_SW_H diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp index f2f712193a..ef6535a878 100644 --- a/servers/physics_3d/gjk_epa.cpp +++ b/servers/physics_3d/gjk_epa.cpp @@ -37,7 +37,7 @@ /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2008 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the @@ -96,7 +96,7 @@ struct sResults { Vector3 witnesses[2]; Vector3 normal; - real_t distance; + real_t distance = 0.0; }; // Shorthands @@ -105,7 +105,7 @@ typedef unsigned char U1; // MinkowskiDiff struct MinkowskiDiff { - const Shape3DSW* m_shapes[2]; + const GodotShape3D* m_shapes[2]; Transform3D transform_A; Transform3D transform_B; @@ -113,10 +113,10 @@ struct MinkowskiDiff { real_t margin_A = 0.0; real_t margin_B = 0.0; - Vector3 (*get_support)(const Shape3DSW*, const Vector3&, real_t); + Vector3 (*get_support)(const GodotShape3D*, const Vector3&, real_t); - void Initialize(const Shape3DSW* shape0, const Transform3D& wtrs0, const real_t margin0, - const Shape3DSW* shape1, const Transform3D& wtrs1, const real_t margin1) { + void Initialize(const GodotShape3D* shape0, const Transform3D& wtrs0, const real_t margin0, + const GodotShape3D* shape1, const Transform3D& wtrs1, const real_t margin1) { m_shapes[0] = shape0; m_shapes[1] = shape1; transform_A = wtrs0; @@ -131,11 +131,11 @@ struct MinkowskiDiff { } } - static Vector3 get_support_without_margin(const Shape3DSW* p_shape, const Vector3& p_dir, real_t p_margin) { + static Vector3 get_support_without_margin(const GodotShape3D* p_shape, const Vector3& p_dir, real_t p_margin) { return p_shape->get_support(p_dir.normalized()); } - static Vector3 get_support_with_margin(const Shape3DSW* p_shape, const Vector3& p_dir, real_t p_margin) { + static Vector3 get_support_with_margin(const GodotShape3D* p_shape, const Vector3& p_dir, real_t p_margin) { Vector3 local_dir_norm = p_dir; if (local_dir_norm.length_squared() < CMP_EPSILON2) { local_dir_norm = Vector3(-1.0, -1.0, -1.0); @@ -862,8 +862,8 @@ struct GJK }; // - static void Initialize( const Shape3DSW* shape0, const Transform3D& wtrs0, real_t margin0, - const Shape3DSW* shape1, const Transform3D& wtrs1, real_t margin1, + static void Initialize( const GodotShape3D* shape0, const Transform3D& wtrs0, real_t margin0, + const GodotShape3D* shape1, const Transform3D& wtrs1, real_t margin1, sResults& results, tShape& shape) { @@ -884,10 +884,10 @@ struct GJK // // -bool Distance( const Shape3DSW* shape0, +bool Distance( const GodotShape3D* shape0, const Transform3D& wtrs0, real_t margin0, - const Shape3DSW* shape1, + const GodotShape3D* shape1, const Transform3D& wtrs1, real_t margin1, const Vector3& guess, @@ -925,10 +925,10 @@ bool Distance( const Shape3DSW* shape0, // -bool Penetration( const Shape3DSW* shape0, +bool Penetration( const GodotShape3D* shape0, const Transform3D& wtrs0, real_t margin0, - const Shape3DSW* shape1, + const GodotShape3D* shape1, const Transform3D& wtrs1, real_t margin1, const Vector3& guess, @@ -993,7 +993,7 @@ bool Penetration( const Shape3DSW* shape0, /* clang-format on */ -bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) { +bool gjk_epa_calculate_distance(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B) { GjkEpa2::sResults res; if (GjkEpa2::Distance(p_shape_A, p_transform_A, 0.0, p_shape_B, p_transform_B, 0.0, p_transform_B.origin - p_transform_A.origin, res)) { @@ -1005,7 +1005,7 @@ bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform3D &p return false; } -bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) { +bool gjk_epa_calculate_penetration(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, GodotCollisionSolver3D::CallbackResult p_result_callback, void *p_userdata, bool p_swap, real_t p_margin_A, real_t p_margin_B) { GjkEpa2::sResults res; if (GjkEpa2::Penetration(p_shape_A, p_transform_A, p_margin_A, p_shape_B, p_transform_B, p_margin_B, p_transform_B.origin - p_transform_A.origin, res)) { diff --git a/servers/physics_3d/gjk_epa.h b/servers/physics_3d/gjk_epa.h index 69e85d2bc0..39a7d03435 100644 --- a/servers/physics_3d/gjk_epa.h +++ b/servers/physics_3d/gjk_epa.h @@ -31,10 +31,10 @@ #ifndef GJK_EPA_H #define GJK_EPA_H -#include "collision_solver_3d_sw.h" -#include "shape_3d_sw.h" +#include "godot_collision_solver_3d.h" +#include "godot_shape_3d.h" -bool gjk_epa_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0); -bool gjk_epa_calculate_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B); +bool gjk_epa_calculate_penetration(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, GodotCollisionSolver3D::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, real_t p_margin_A = 0.0, real_t p_margin_B = 0.0); +bool gjk_epa_calculate_distance(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_result_A, Vector3 &r_result_B); #endif diff --git a/servers/physics_3d/area_3d_sw.cpp b/servers/physics_3d/godot_area_3d.cpp index c9e8bcb8ca..d4e14b8d85 100644 --- a/servers/physics_3d/area_3d_sw.cpp +++ b/servers/physics_3d/godot_area_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* area_3d_sw.cpp */ +/* godot_area_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,39 +28,40 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "area_3d_sw.h" -#include "body_3d_sw.h" -#include "soft_body_3d_sw.h" -#include "space_3d_sw.h" +#include "godot_area_3d.h" -Area3DSW::BodyKey::BodyKey(SoftBody3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +#include "godot_body_3d.h" +#include "godot_soft_body_3d.h" +#include "godot_space_3d.h" + +GodotArea3D::BodyKey::BodyKey(GodotSoftBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { rid = p_body->get_self(); instance_id = p_body->get_instance_id(); body_shape = p_body_shape; area_shape = p_area_shape; } -Area3DSW::BodyKey::BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +GodotArea3D::BodyKey::BodyKey(GodotBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { rid = p_body->get_self(); instance_id = p_body->get_instance_id(); body_shape = p_body_shape; area_shape = p_area_shape; } -Area3DSW::BodyKey::BodyKey(Area3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +GodotArea3D::BodyKey::BodyKey(GodotArea3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { rid = p_body->get_self(); instance_id = p_body->get_instance_id(); body_shape = p_body_shape; area_shape = p_area_shape; } -void Area3DSW::_shapes_changed() { +void GodotArea3D::_shapes_changed() { if (!moved_list.in_list() && get_space()) { get_space()->area_add_to_moved_list(&moved_list); } } -void Area3DSW::set_transform(const Transform3D &p_transform) { +void GodotArea3D::set_transform(const Transform3D &p_transform) { if (!moved_list.in_list() && get_space()) { get_space()->area_add_to_moved_list(&moved_list); } @@ -69,7 +70,7 @@ void Area3DSW::set_transform(const Transform3D &p_transform) { _set_inv_transform(p_transform.affine_inverse()); } -void Area3DSW::set_space(Space3DSW *p_space) { +void GodotArea3D::set_space(GodotSpace3D *p_space) { if (get_space()) { if (monitor_query_list.in_list()) { get_space()->area_remove_from_monitor_query_list(&monitor_query_list); @@ -85,16 +86,16 @@ void Area3DSW::set_space(Space3DSW *p_space) { _set_space(p_space); } -void Area3DSW::set_monitor_callback(ObjectID p_id, const StringName &p_method) { - if (p_id == monitor_callback_id) { - monitor_callback_method = p_method; +void GodotArea3D::set_monitor_callback(const Callable &p_callback) { + ObjectID id = p_callback.get_object_id(); + if (id == monitor_callback.get_object_id()) { + monitor_callback = p_callback; return; } _unregister_shapes(); - monitor_callback_id = p_id; - monitor_callback_method = p_method; + monitor_callback = p_callback; monitored_bodies.clear(); monitored_areas.clear(); @@ -106,16 +107,16 @@ void Area3DSW::set_monitor_callback(ObjectID p_id, const StringName &p_method) { } } -void Area3DSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_method) { - if (p_id == area_monitor_callback_id) { - area_monitor_callback_method = p_method; +void GodotArea3D::set_area_monitor_callback(const Callable &p_callback) { + ObjectID id = p_callback.get_object_id(); + if (id == area_monitor_callback.get_object_id()) { + area_monitor_callback = p_callback; return; } _unregister_shapes(); - area_monitor_callback_id = p_id; - area_monitor_callback_method = p_method; + area_monitor_callback = p_callback; monitored_bodies.clear(); monitored_areas.clear(); @@ -127,18 +128,21 @@ void Area3DSW::set_area_monitor_callback(ObjectID p_id, const StringName &p_meth } } -void Area3DSW::set_space_override_mode(PhysicsServer3D::AreaSpaceOverrideMode p_mode) { - bool do_override = p_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED; - if (do_override == (space_override_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED)) { +void GodotArea3D::_set_space_override_mode(PhysicsServer3D::AreaSpaceOverrideMode &r_mode, PhysicsServer3D::AreaSpaceOverrideMode p_new_mode) { + bool do_override = p_new_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED; + if (do_override == (r_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED)) { return; } _unregister_shapes(); - space_override_mode = p_mode; + r_mode = p_new_mode; _shape_changed(); } -void Area3DSW::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) { +void GodotArea3D::set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value) { switch (p_param) { + case PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE: + _set_space_override_mode(gravity_override_mode, (PhysicsServer3D::AreaSpaceOverrideMode)(int)p_value); + break; case PhysicsServer3D::AREA_PARAM_GRAVITY: gravity = p_value; break; @@ -154,9 +158,15 @@ void Area3DSW::set_param(PhysicsServer3D::AreaParameter p_param, const Variant & case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: point_attenuation = p_value; break; + case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE: + _set_space_override_mode(linear_damping_override_mode, (PhysicsServer3D::AreaSpaceOverrideMode)(int)p_value); + break; case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: linear_damp = p_value; break; + case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE: + _set_space_override_mode(angular_damping_override_mode, (PhysicsServer3D::AreaSpaceOverrideMode)(int)p_value); + break; case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: angular_damp = p_value; break; @@ -180,8 +190,10 @@ void Area3DSW::set_param(PhysicsServer3D::AreaParameter p_param, const Variant & } } -Variant Area3DSW::get_param(PhysicsServer3D::AreaParameter p_param) const { +Variant GodotArea3D::get_param(PhysicsServer3D::AreaParameter p_param) const { switch (p_param) { + case PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE: + return gravity_override_mode; case PhysicsServer3D::AREA_PARAM_GRAVITY: return gravity; case PhysicsServer3D::AREA_PARAM_GRAVITY_VECTOR: @@ -192,8 +204,12 @@ Variant Area3DSW::get_param(PhysicsServer3D::AreaParameter p_param) const { return gravity_distance_scale; case PhysicsServer3D::AREA_PARAM_GRAVITY_POINT_ATTENUATION: return point_attenuation; + case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE: + return linear_damping_override_mode; case PhysicsServer3D::AREA_PARAM_LINEAR_DAMP: return linear_damp; + case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE: + return angular_damping_override_mode; case PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP: return angular_damp; case PhysicsServer3D::AREA_PARAM_PRIORITY: @@ -211,7 +227,7 @@ Variant Area3DSW::get_param(PhysicsServer3D::AreaParameter p_param) const { return Variant(); } -void Area3DSW::_queue_monitor_update() { +void GodotArea3D::_queue_monitor_update() { ERR_FAIL_COND(!get_space()); if (!monitor_query_list.in_list()) { @@ -219,92 +235,91 @@ void Area3DSW::_queue_monitor_update() { } } -void Area3DSW::set_monitorable(bool p_monitorable) { +void GodotArea3D::set_monitorable(bool p_monitorable) { if (monitorable == p_monitorable) { return; } monitorable = p_monitorable; _set_static(!monitorable); + _shapes_changed(); } -void Area3DSW::call_queries() { - if (monitor_callback_id.is_valid() && !monitored_bodies.is_empty()) { - Variant res[5]; - Variant *resptr[5]; - for (int i = 0; i < 5; i++) { - resptr[i] = &res[i]; - } +void GodotArea3D::call_queries() { + if (!monitor_callback.is_null() && !monitored_bodies.is_empty()) { + if (monitor_callback.is_valid()) { + Variant res[5]; + Variant *resptr[5]; + for (int i = 0; i < 5; i++) { + resptr[i] = &res[i]; + } - Object *obj = ObjectDB::get_instance(monitor_callback_id); - if (!obj) { - monitored_bodies.clear(); - monitor_callback_id = ObjectID(); - return; - } + for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) { + if (E->get().state == 0) { // Nothing happened + Map<BodyKey, BodyState>::Element *next = E->next(); + monitored_bodies.erase(E); + E = next; + continue; + } + + res[0] = E->get().state > 0 ? PhysicsServer3D::AREA_BODY_ADDED : PhysicsServer3D::AREA_BODY_REMOVED; + res[1] = E->key().rid; + res[2] = E->key().instance_id; + res[3] = E->key().body_shape; + res[4] = E->key().area_shape; - for (Map<BodyKey, BodyState>::Element *E = monitored_bodies.front(); E;) { - if (E->get().state == 0) { // Nothing happened Map<BodyKey, BodyState>::Element *next = E->next(); monitored_bodies.erase(E); E = next; - continue; - } - res[0] = E->get().state > 0 ? PhysicsServer3D::AREA_BODY_ADDED : PhysicsServer3D::AREA_BODY_REMOVED; - res[1] = E->key().rid; - res[2] = E->key().instance_id; - res[3] = E->key().body_shape; - res[4] = E->key().area_shape; - - Map<BodyKey, BodyState>::Element *next = E->next(); - monitored_bodies.erase(E); - E = next; - - Callable::CallError ce; - obj->call(monitor_callback_method, (const Variant **)resptr, 5, ce); + Callable::CallError ce; + Variant ret; + monitor_callback.call((const Variant **)resptr, 5, ret, ce); + } + } else { + monitored_bodies.clear(); + monitor_callback = Callable(); } } - if (area_monitor_callback_id.is_valid() && !monitored_areas.is_empty()) { - Variant res[5]; - Variant *resptr[5]; - for (int i = 0; i < 5; i++) { - resptr[i] = &res[i]; - } + if (!area_monitor_callback.is_null() && !monitored_areas.is_empty()) { + if (area_monitor_callback.is_valid()) { + Variant res[5]; + Variant *resptr[5]; + for (int i = 0; i < 5; i++) { + resptr[i] = &res[i]; + } - Object *obj = ObjectDB::get_instance(area_monitor_callback_id); - if (!obj) { - monitored_areas.clear(); - area_monitor_callback_id = ObjectID(); - return; - } + for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) { + if (E->get().state == 0) { // Nothing happened + Map<BodyKey, BodyState>::Element *next = E->next(); + monitored_areas.erase(E); + E = next; + continue; + } + + res[0] = E->get().state > 0 ? PhysicsServer3D::AREA_BODY_ADDED : PhysicsServer3D::AREA_BODY_REMOVED; + res[1] = E->key().rid; + res[2] = E->key().instance_id; + res[3] = E->key().body_shape; + res[4] = E->key().area_shape; - for (Map<BodyKey, BodyState>::Element *E = monitored_areas.front(); E;) { - if (E->get().state == 0) { // Nothing happened Map<BodyKey, BodyState>::Element *next = E->next(); monitored_areas.erase(E); E = next; - continue; - } - - res[0] = E->get().state > 0 ? PhysicsServer3D::AREA_BODY_ADDED : PhysicsServer3D::AREA_BODY_REMOVED; - res[1] = E->key().rid; - res[2] = E->key().instance_id; - res[3] = E->key().body_shape; - res[4] = E->key().area_shape; - - Map<BodyKey, BodyState>::Element *next = E->next(); - monitored_areas.erase(E); - E = next; - Callable::CallError ce; - obj->call(area_monitor_callback_method, (const Variant **)resptr, 5, ce); + Callable::CallError ce; + Variant ret; + area_monitor_callback.call((const Variant **)resptr, 5, ret, ce); + } + } else { + monitored_areas.clear(); + area_monitor_callback = Callable(); } } } -void Area3DSW::compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) const { +void GodotArea3D::compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) const { if (is_gravity_point()) { const real_t gravity_distance_scale = get_gravity_distance_scale(); Vector3 v = get_transform().xform(get_gravity_vector()) - p_position; @@ -324,23 +339,13 @@ void Area3DSW::compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) co } } -Area3DSW::Area3DSW() : - CollisionObject3DSW(TYPE_AREA), +GodotArea3D::GodotArea3D() : + GodotCollisionObject3D(TYPE_AREA), monitor_query_list(this), moved_list(this) { _set_static(true); //areas are never active - space_override_mode = PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED; - gravity = 9.80665; - gravity_vector = Vector3(0, -1, 0); - gravity_is_point = false; - gravity_distance_scale = 0; - point_attenuation = 1; - angular_damp = 0.1; - linear_damp = 0.1; - priority = 0; set_ray_pickable(false); - monitorable = false; } -Area3DSW::~Area3DSW() { +GodotArea3D::~GodotArea3D() { } diff --git a/servers/physics_3d/area_3d_sw.h b/servers/physics_3d/godot_area_3d.h index d5f1e60119..0dcf89b2b4 100644 --- a/servers/physics_3d/area_3d_sw.h +++ b/servers/physics_3d/godot_area_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* area_3d_sw.h */ +/* godot_area_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,48 +28,49 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AREA_SW_H -#define AREA_SW_H +#ifndef GODOT_AREA_3D_H +#define GODOT_AREA_3D_H + +#include "godot_collision_object_3d.h" -#include "collision_object_3d_sw.h" #include "core/templates/self_list.h" #include "servers/physics_server_3d.h" -class Space3DSW; -class Body3DSW; -class SoftBody3DSW; -class Constraint3DSW; - -class Area3DSW : public CollisionObject3DSW { - PhysicsServer3D::AreaSpaceOverrideMode space_override_mode; - real_t gravity; - Vector3 gravity_vector; - bool gravity_is_point; - real_t gravity_distance_scale; - real_t point_attenuation; - real_t linear_damp; - real_t angular_damp; +class GodotSpace3D; +class GodotBody3D; +class GodotSoftBody3D; +class GodotConstraint3D; + +class GodotArea3D : public GodotCollisionObject3D { + PhysicsServer3D::AreaSpaceOverrideMode gravity_override_mode = PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED; + PhysicsServer3D::AreaSpaceOverrideMode linear_damping_override_mode = PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED; + PhysicsServer3D::AreaSpaceOverrideMode angular_damping_override_mode = PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED; + + real_t gravity = 9.80665; + Vector3 gravity_vector = Vector3(0, -1, 0); + bool gravity_is_point = false; + real_t gravity_distance_scale = 0.0; + real_t point_attenuation = 1.0; + real_t linear_damp = 0.1; + real_t angular_damp = 0.1; real_t wind_force_magnitude = 0.0; real_t wind_attenuation_factor = 0.0; Vector3 wind_source; Vector3 wind_direction; - int priority; - bool monitorable; - - ObjectID monitor_callback_id; - StringName monitor_callback_method; + int priority = 0; + bool monitorable = false; - ObjectID area_monitor_callback_id; - StringName area_monitor_callback_method; + Callable monitor_callback; + Callable area_monitor_callback; - SelfList<Area3DSW> monitor_query_list; - SelfList<Area3DSW> moved_list; + SelfList<GodotArea3D> monitor_query_list; + SelfList<GodotArea3D> moved_list; struct BodyKey { RID rid; ObjectID instance_id; - uint32_t body_shape; - uint32_t area_shape; + uint32_t body_shape = 0; + uint32_t area_shape = 0; _FORCE_INLINE_ bool operator<(const BodyKey &p_key) const { if (rid == p_key.rid) { @@ -84,49 +85,47 @@ class Area3DSW : public CollisionObject3DSW { } _FORCE_INLINE_ BodyKey() {} - BodyKey(SoftBody3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); - BodyKey(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); - BodyKey(Area3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + BodyKey(GodotSoftBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + BodyKey(GodotBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + BodyKey(GodotArea3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); }; struct BodyState { - int state; + int state = 0; _FORCE_INLINE_ void inc() { state++; } _FORCE_INLINE_ void dec() { state--; } - _FORCE_INLINE_ BodyState() { state = 0; } }; Map<BodyKey, BodyState> monitored_soft_bodies; Map<BodyKey, BodyState> monitored_bodies; Map<BodyKey, BodyState> monitored_areas; - Set<Constraint3DSW *> constraints; + Set<GodotConstraint3D *> constraints; virtual void _shapes_changed(); void _queue_monitor_update(); + void _set_space_override_mode(PhysicsServer3D::AreaSpaceOverrideMode &r_mode, PhysicsServer3D::AreaSpaceOverrideMode p_new_mode); + public: - void set_monitor_callback(ObjectID p_id, const StringName &p_method); - _FORCE_INLINE_ bool has_monitor_callback() const { return monitor_callback_id.is_valid(); } + void set_monitor_callback(const Callable &p_callback); + _FORCE_INLINE_ bool has_monitor_callback() const { return !monitor_callback.is_null(); } - void set_area_monitor_callback(ObjectID p_id, const StringName &p_method); - _FORCE_INLINE_ bool has_area_monitor_callback() const { return area_monitor_callback_id.is_valid(); } + void set_area_monitor_callback(const Callable &p_callback); + _FORCE_INLINE_ bool has_area_monitor_callback() const { return !area_monitor_callback.is_null(); } - _FORCE_INLINE_ void add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); - _FORCE_INLINE_ void remove_body_from_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void add_body_to_query(GodotBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void remove_body_from_query(GodotBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape); - _FORCE_INLINE_ void add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape); - _FORCE_INLINE_ void remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void add_soft_body_to_query(GodotSoftBody3D *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape); + _FORCE_INLINE_ void remove_soft_body_from_query(GodotSoftBody3D *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape); - _FORCE_INLINE_ void add_area_to_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape); - _FORCE_INLINE_ void remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape); + _FORCE_INLINE_ void add_area_to_query(GodotArea3D *p_area, uint32_t p_area_shape, uint32_t p_self_shape); + _FORCE_INLINE_ void remove_area_from_query(GodotArea3D *p_area, uint32_t p_area_shape, uint32_t p_self_shape); void set_param(PhysicsServer3D::AreaParameter p_param, const Variant &p_value); Variant get_param(PhysicsServer3D::AreaParameter p_param) const; - void set_space_override_mode(PhysicsServer3D::AreaSpaceOverrideMode p_mode); - PhysicsServer3D::AreaSpaceOverrideMode get_space_override_mode() const { return space_override_mode; } - _FORCE_INLINE_ void set_gravity(real_t p_gravity) { gravity = p_gravity; } _FORCE_INLINE_ real_t get_gravity() const { return gravity; } @@ -163,9 +162,9 @@ public: _FORCE_INLINE_ void set_wind_direction(const Vector3 &p_wind_direction) { wind_direction = p_wind_direction; } _FORCE_INLINE_ const Vector3 &get_wind_direction() const { return wind_direction; } - _FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint) { constraints.insert(p_constraint); } - _FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraints.erase(p_constraint); } - _FORCE_INLINE_ const Set<Constraint3DSW *> &get_constraints() const { return constraints; } + _FORCE_INLINE_ void add_constraint(GodotConstraint3D *p_constraint) { constraints.insert(p_constraint); } + _FORCE_INLINE_ void remove_constraint(GodotConstraint3D *p_constraint) { constraints.erase(p_constraint); } + _FORCE_INLINE_ const Set<GodotConstraint3D *> &get_constraints() const { return constraints; } _FORCE_INLINE_ void clear_constraints() { constraints.clear(); } void set_monitorable(bool p_monitorable); @@ -173,17 +172,17 @@ public: void set_transform(const Transform3D &p_transform); - void set_space(Space3DSW *p_space); + void set_space(GodotSpace3D *p_space); void call_queries(); void compute_gravity(const Vector3 &p_position, Vector3 &r_gravity) const; - Area3DSW(); - ~Area3DSW(); + GodotArea3D(); + ~GodotArea3D(); }; -void Area3DSW::add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) { +void GodotArea3D::add_soft_body_to_query(GodotSoftBody3D *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) { BodyKey bk(p_soft_body, p_soft_body_shape, p_area_shape); monitored_soft_bodies[bk].inc(); if (!monitor_query_list.in_list()) { @@ -191,7 +190,7 @@ void Area3DSW::add_soft_body_to_query(SoftBody3DSW *p_soft_body, uint32_t p_soft } } -void Area3DSW::remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) { +void GodotArea3D::remove_soft_body_from_query(GodotSoftBody3D *p_soft_body, uint32_t p_soft_body_shape, uint32_t p_area_shape) { BodyKey bk(p_soft_body, p_soft_body_shape, p_area_shape); monitored_soft_bodies[bk].dec(); if (!monitor_query_list.in_list()) { @@ -199,7 +198,7 @@ void Area3DSW::remove_soft_body_from_query(SoftBody3DSW *p_soft_body, uint32_t p } } -void Area3DSW::add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +void GodotArea3D::add_body_to_query(GodotBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { BodyKey bk(p_body, p_body_shape, p_area_shape); monitored_bodies[bk].inc(); if (!monitor_query_list.in_list()) { @@ -207,7 +206,7 @@ void Area3DSW::add_body_to_query(Body3DSW *p_body, uint32_t p_body_shape, uint32 } } -void Area3DSW::remove_body_from_query(Body3DSW *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { +void GodotArea3D::remove_body_from_query(GodotBody3D *p_body, uint32_t p_body_shape, uint32_t p_area_shape) { BodyKey bk(p_body, p_body_shape, p_area_shape); monitored_bodies[bk].dec(); if (!monitor_query_list.in_list()) { @@ -215,7 +214,7 @@ void Area3DSW::remove_body_from_query(Body3DSW *p_body, uint32_t p_body_shape, u } } -void Area3DSW::add_area_to_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) { +void GodotArea3D::add_area_to_query(GodotArea3D *p_area, uint32_t p_area_shape, uint32_t p_self_shape) { BodyKey bk(p_area, p_area_shape, p_self_shape); monitored_areas[bk].inc(); if (!monitor_query_list.in_list()) { @@ -223,7 +222,7 @@ void Area3DSW::add_area_to_query(Area3DSW *p_area, uint32_t p_area_shape, uint32 } } -void Area3DSW::remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, uint32_t p_self_shape) { +void GodotArea3D::remove_area_from_query(GodotArea3D *p_area, uint32_t p_area_shape, uint32_t p_self_shape) { BodyKey bk(p_area, p_area_shape, p_self_shape); monitored_areas[bk].dec(); if (!monitor_query_list.in_list()) { @@ -232,15 +231,15 @@ void Area3DSW::remove_area_from_query(Area3DSW *p_area, uint32_t p_area_shape, u } struct AreaCMP { - Area3DSW *area; - int refCount; + GodotArea3D *area = nullptr; + int refCount = 0; _FORCE_INLINE_ bool operator==(const AreaCMP &p_cmp) const { return area->get_self() == p_cmp.area->get_self(); } _FORCE_INLINE_ bool operator<(const AreaCMP &p_cmp) const { return area->get_priority() < p_cmp.area->get_priority(); } _FORCE_INLINE_ AreaCMP() {} - _FORCE_INLINE_ AreaCMP(Area3DSW *p_area) { + _FORCE_INLINE_ AreaCMP(GodotArea3D *p_area) { area = p_area; refCount = 1; } }; -#endif // AREA__SW_H +#endif // GODOT_AREA_3D_H diff --git a/servers/physics_3d/area_pair_3d_sw.cpp b/servers/physics_3d/godot_area_pair_3d.cpp index bf4f0035b4..58188565e3 100644 --- a/servers/physics_3d/area_pair_3d_sw.cpp +++ b/servers/physics_3d/godot_area_pair_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* area_pair_3d_sw.cpp */ +/* godot_area_pair_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,20 +28,29 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "area_pair_3d_sw.h" -#include "collision_solver_3d_sw.h" +#include "godot_area_pair_3d.h" -bool AreaPair3DSW::setup(real_t p_step) { +#include "godot_collision_solver_3d.h" + +bool GodotAreaPair3D::setup(real_t p_step) { bool result = false; - if (area->collides_with(body) && CollisionSolver3DSW::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) { + if (area->collides_with(body) && GodotCollisionSolver3D::solve_static(body->get_shape(body_shape), body->get_transform() * body->get_shape_transform(body_shape), area->get_shape(area_shape), area->get_transform() * area->get_shape_transform(area_shape), nullptr, this)) { result = true; } process_collision = false; + has_space_override = false; if (result != colliding) { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { - process_collision = true; - } else if (area->has_monitor_callback()) { + if ((int)area->get_param(PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE) != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + has_space_override = true; + } else if ((int)area->get_param(PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE) != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + has_space_override = true; + } else if ((int)area->get_param(PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE) != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + has_space_override = true; + } + process_collision = has_space_override; + + if (area->has_monitor_callback()) { process_collision = true; } @@ -51,13 +60,13 @@ bool AreaPair3DSW::setup(real_t p_step) { return process_collision; } -bool AreaPair3DSW::pre_solve(real_t p_step) { +bool GodotAreaPair3D::pre_solve(real_t p_step) { if (!process_collision) { return false; } if (colliding) { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { body->add_area(area); } @@ -65,7 +74,7 @@ bool AreaPair3DSW::pre_solve(real_t p_step) { area->add_body_to_query(body, body_shape, area_shape); } } else { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { body->remove_area(area); } @@ -77,11 +86,11 @@ bool AreaPair3DSW::pre_solve(real_t p_step) { return false; // Never do any post solving. } -void AreaPair3DSW::solve(real_t p_step) { +void GodotAreaPair3D::solve(real_t p_step) { // Nothing to do. } -AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape) { +GodotAreaPair3D::GodotAreaPair3D(GodotBody3D *p_body, int p_body_shape, GodotArea3D *p_area, int p_area_shape) { body = p_body; area = p_area; body_shape = p_body_shape; @@ -93,9 +102,9 @@ AreaPair3DSW::AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, } } -AreaPair3DSW::~AreaPair3DSW() { +GodotAreaPair3D::~GodotAreaPair3D() { if (colliding) { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { body->remove_area(area); } if (area->has_monitor_callback()) { @@ -108,10 +117,10 @@ AreaPair3DSW::~AreaPair3DSW() { //////////////////////////////////////////////////// -bool Area2Pair3DSW::setup(real_t p_step) { +bool GodotArea2Pair3D::setup(real_t p_step) { bool result_a = area_a->collides_with(area_b); bool result_b = area_b->collides_with(area_a); - if ((result_a || result_b) && !CollisionSolver3DSW::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) { + if ((result_a || result_b) && !GodotCollisionSolver3D::solve_static(area_a->get_shape(shape_a), area_a->get_transform() * area_a->get_shape_transform(shape_a), area_b->get_shape(shape_b), area_b->get_transform() * area_b->get_shape_transform(shape_b), nullptr, this)) { result_a = false; result_b = false; } @@ -120,7 +129,7 @@ bool Area2Pair3DSW::setup(real_t p_step) { process_collision_a = false; if (result_a != colliding_a) { - if (area_a->has_area_monitor_callback() && area_b->is_monitorable()) { + if (area_a->has_area_monitor_callback() && area_b_monitorable) { process_collision_a = true; process_collision = true; } @@ -129,7 +138,7 @@ bool Area2Pair3DSW::setup(real_t p_step) { process_collision_b = false; if (result_b != colliding_b) { - if (area_b->has_area_monitor_callback() && area_a->is_monitorable()) { + if (area_b->has_area_monitor_callback() && area_a_monitorable) { process_collision_b = true; process_collision = true; } @@ -139,7 +148,7 @@ bool Area2Pair3DSW::setup(real_t p_step) { return process_collision; } -bool Area2Pair3DSW::pre_solve(real_t p_step) { +bool GodotArea2Pair3D::pre_solve(real_t p_step) { if (process_collision_a) { if (colliding_a) { area_a->add_area_to_query(area_b, shape_b, shape_a); @@ -159,28 +168,30 @@ bool Area2Pair3DSW::pre_solve(real_t p_step) { return false; // Never do any post solving. } -void Area2Pair3DSW::solve(real_t p_step) { +void GodotArea2Pair3D::solve(real_t p_step) { // Nothing to do. } -Area2Pair3DSW::Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b) { +GodotArea2Pair3D::GodotArea2Pair3D(GodotArea3D *p_area_a, int p_shape_a, GodotArea3D *p_area_b, int p_shape_b) { area_a = p_area_a; area_b = p_area_b; shape_a = p_shape_a; shape_b = p_shape_b; + area_a_monitorable = area_a->is_monitorable(); + area_b_monitorable = area_b->is_monitorable(); area_a->add_constraint(this); area_b->add_constraint(this); } -Area2Pair3DSW::~Area2Pair3DSW() { +GodotArea2Pair3D::~GodotArea2Pair3D() { if (colliding_a) { - if (area_a->has_area_monitor_callback()) { + if (area_a->has_area_monitor_callback() && area_b_monitorable) { area_a->remove_area_from_query(area_b, shape_b, shape_a); } } if (colliding_b) { - if (area_b->has_area_monitor_callback()) { + if (area_b->has_area_monitor_callback() && area_a_monitorable) { area_b->remove_area_from_query(area_a, shape_a, shape_b); } } @@ -191,11 +202,11 @@ Area2Pair3DSW::~Area2Pair3DSW() { //////////////////////////////////////////////////// -bool AreaSoftBodyPair3DSW::setup(real_t p_step) { +bool GodotAreaSoftBodyPair3D::setup(real_t p_step) { bool result = false; if ( area->collides_with(soft_body) && - CollisionSolver3DSW::solve_static( + GodotCollisionSolver3D::solve_static( soft_body->get_shape(soft_body_shape), soft_body->get_transform() * soft_body->get_shape_transform(soft_body_shape), area->get_shape(area_shape), @@ -206,10 +217,15 @@ bool AreaSoftBodyPair3DSW::setup(real_t p_step) { } process_collision = false; + has_space_override = false; if (result != colliding) { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { - process_collision = true; - } else if (area->has_monitor_callback()) { + if ((int)area->get_param(PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE) != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + has_space_override = true; + } else if (area->get_wind_force_magnitude() > CMP_EPSILON) { + has_space_override = true; + } + + if (area->has_monitor_callback()) { process_collision = true; } @@ -219,13 +235,13 @@ bool AreaSoftBodyPair3DSW::setup(real_t p_step) { return process_collision; } -bool AreaSoftBodyPair3DSW::pre_solve(real_t p_step) { +bool GodotAreaSoftBodyPair3D::pre_solve(real_t p_step) { if (!process_collision) { return false; } if (colliding) { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { soft_body->add_area(area); } @@ -233,7 +249,7 @@ bool AreaSoftBodyPair3DSW::pre_solve(real_t p_step) { area->add_soft_body_to_query(soft_body, soft_body_shape, area_shape); } } else { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { soft_body->remove_area(area); } @@ -245,11 +261,11 @@ bool AreaSoftBodyPair3DSW::pre_solve(real_t p_step) { return false; // Never do any post solving. } -void AreaSoftBodyPair3DSW::solve(real_t p_step) { +void GodotAreaSoftBodyPair3D::solve(real_t p_step) { // Nothing to do. } -AreaSoftBodyPair3DSW::AreaSoftBodyPair3DSW(SoftBody3DSW *p_soft_body, int p_soft_body_shape, Area3DSW *p_area, int p_area_shape) { +GodotAreaSoftBodyPair3D::GodotAreaSoftBodyPair3D(GodotSoftBody3D *p_soft_body, int p_soft_body_shape, GodotArea3D *p_area, int p_area_shape) { soft_body = p_soft_body; area = p_area; soft_body_shape = p_soft_body_shape; @@ -258,9 +274,9 @@ AreaSoftBodyPair3DSW::AreaSoftBodyPair3DSW(SoftBody3DSW *p_soft_body, int p_soft area->add_constraint(this); } -AreaSoftBodyPair3DSW::~AreaSoftBodyPair3DSW() { +GodotAreaSoftBodyPair3D::~GodotAreaSoftBodyPair3D() { if (colliding) { - if (area->get_space_override_mode() != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + if (has_space_override) { soft_body->remove_area(area); } if (area->has_monitor_callback()) { diff --git a/servers/physics_3d/area_pair_3d_sw.h b/servers/physics_3d/godot_area_pair_3d.h index 4572dcbb23..4237e7722e 100644 --- a/servers/physics_3d/area_pair_3d_sw.h +++ b/servers/physics_3d/godot_area_pair_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* area_pair_3d_sw.h */ +/* godot_area_pair_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,65 +28,69 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef AREA_PAIR_SW_H -#define AREA_PAIR_SW_H +#ifndef GODOT_AREA_PAIR_3D_H +#define GODOT_AREA_PAIR_3D_H -#include "area_3d_sw.h" -#include "body_3d_sw.h" -#include "constraint_3d_sw.h" -#include "soft_body_3d_sw.h" +#include "godot_area_3d.h" +#include "godot_body_3d.h" +#include "godot_constraint_3d.h" +#include "godot_soft_body_3d.h" -class AreaPair3DSW : public Constraint3DSW { - Body3DSW *body; - Area3DSW *area; +class GodotAreaPair3D : public GodotConstraint3D { + GodotBody3D *body; + GodotArea3D *area; int body_shape; int area_shape; bool colliding = false; bool process_collision = false; + bool has_space_override = false; public: virtual bool setup(real_t p_step) override; virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - AreaPair3DSW(Body3DSW *p_body, int p_body_shape, Area3DSW *p_area, int p_area_shape); - ~AreaPair3DSW(); + GodotAreaPair3D(GodotBody3D *p_body, int p_body_shape, GodotArea3D *p_area, int p_area_shape); + ~GodotAreaPair3D(); }; -class Area2Pair3DSW : public Constraint3DSW { - Area3DSW *area_a; - Area3DSW *area_b; +class GodotArea2Pair3D : public GodotConstraint3D { + GodotArea3D *area_a; + GodotArea3D *area_b; int shape_a; int shape_b; bool colliding_a = false; bool colliding_b = false; bool process_collision_a = false; bool process_collision_b = false; + bool area_a_monitorable; + bool area_b_monitorable; public: virtual bool setup(real_t p_step) override; virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - Area2Pair3DSW(Area3DSW *p_area_a, int p_shape_a, Area3DSW *p_area_b, int p_shape_b); - ~Area2Pair3DSW(); + GodotArea2Pair3D(GodotArea3D *p_area_a, int p_shape_a, GodotArea3D *p_area_b, int p_shape_b); + ~GodotArea2Pair3D(); }; -class AreaSoftBodyPair3DSW : public Constraint3DSW { - SoftBody3DSW *soft_body; - Area3DSW *area; +class GodotAreaSoftBodyPair3D : public GodotConstraint3D { + GodotSoftBody3D *soft_body; + GodotArea3D *area; int soft_body_shape; int area_shape; bool colliding = false; bool process_collision = false; + bool has_space_override = false; public: virtual bool setup(real_t p_step) override; virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - AreaSoftBodyPair3DSW(SoftBody3DSW *p_sof_body, int p_soft_body_shape, Area3DSW *p_area, int p_area_shape); - ~AreaSoftBodyPair3DSW(); + GodotAreaSoftBodyPair3D(GodotSoftBody3D *p_sof_body, int p_soft_body_shape, GodotArea3D *p_area, int p_area_shape); + ~GodotAreaSoftBodyPair3D(); }; -#endif // AREA_PAIR__SW_H +#endif // GODOT_AREA_PAIR_3D_H diff --git a/servers/physics_3d/body_3d_sw.cpp b/servers/physics_3d/godot_body_3d.cpp index 7f62e4eb85..40d946655d 100644 --- a/servers/physics_3d/body_3d_sw.cpp +++ b/servers/physics_3d/godot_body_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_3d_sw.cpp */ +/* godot_body_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,23 +28,23 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "body_3d_sw.h" +#include "godot_body_3d.h" -#include "area_3d_sw.h" -#include "body_direct_state_3d_sw.h" -#include "space_3d_sw.h" +#include "godot_area_3d.h" +#include "godot_body_direct_state_3d.h" +#include "godot_space_3d.h" -void Body3DSW::_update_inertia() { - if (get_space() && !inertia_update_list.in_list()) { - get_space()->body_add_to_inertia_update_list(&inertia_update_list); +void GodotBody3D::_mass_properties_changed() { + if (get_space() && !mass_properties_update_list.in_list() && (calculate_inertia || calculate_center_of_mass)) { + get_space()->body_add_to_mass_properties_update_list(&mass_properties_update_list); } } -void Body3DSW::_update_transform_dependant() { +void GodotBody3D::_update_transform_dependent() { center_of_mass = get_transform().basis.xform(center_of_mass_local); principal_inertia_axes = get_transform().basis * principal_inertia_axes_local; - // update inertia tensor + // Update inertia tensor. Basis tb = principal_inertia_axes; Basis tbt = tb.transposed(); Basis diag; @@ -52,74 +52,95 @@ void Body3DSW::_update_transform_dependant() { _inv_inertia_tensor = tb * diag * tbt; } -void Body3DSW::update_inertias() { +void GodotBody3D::update_mass_properties() { // Update shapes and motions. switch (mode) { case PhysicsServer3D::BODY_MODE_DYNAMIC: { - // Update tensor for all shapes, not the best way but should be somehow OK. (inspired from bullet) real_t total_area = 0; - for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } + total_area += get_shape_area(i); } - // We have to recompute the center of mass. - center_of_mass_local.zero(); + if (calculate_center_of_mass) { + // We have to recompute the center of mass. + center_of_mass_local.zero(); - if (total_area != 0.0) { - for (int i = 0; i < get_shape_count(); i++) { - real_t area = get_shape_area(i); + if (total_area != 0.0) { + for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } - real_t mass = area * this->mass / total_area; + real_t area = get_shape_area(i); - // NOTE: we assume that the shape origin is also its center of mass. - center_of_mass_local += mass * get_shape_transform(i).origin; - } + real_t mass = area * this->mass / total_area; + + // NOTE: we assume that the shape origin is also its center of mass. + center_of_mass_local += mass * get_shape_transform(i).origin; + } - center_of_mass_local /= mass; + center_of_mass_local /= mass; + } } - // Recompute the inertia tensor. - Basis inertia_tensor; - inertia_tensor.set_zero(); - bool inertia_set = false; + if (calculate_inertia) { + // Recompute the inertia tensor. + Basis inertia_tensor; + inertia_tensor.set_zero(); + bool inertia_set = false; - for (int i = 0; i < get_shape_count(); i++) { - if (is_shape_disabled(i)) { - continue; - } + for (int i = 0; i < get_shape_count(); i++) { + if (is_shape_disabled(i)) { + continue; + } - real_t area = get_shape_area(i); - if (area == 0.0) { - continue; - } + real_t area = get_shape_area(i); + if (area == 0.0) { + continue; + } - inertia_set = true; + inertia_set = true; - const Shape3DSW *shape = get_shape(i); + const GodotShape3D *shape = get_shape(i); - real_t mass = area * this->mass / total_area; + real_t mass = area * this->mass / total_area; - Basis shape_inertia_tensor = shape->get_moment_of_inertia(mass).to_diagonal_matrix(); - Transform3D shape_transform = get_shape_transform(i); - Basis shape_basis = shape_transform.basis.orthonormalized(); + Basis shape_inertia_tensor = Basis::from_scale(shape->get_moment_of_inertia(mass)); + Transform3D shape_transform = get_shape_transform(i); + Basis shape_basis = shape_transform.basis.orthonormalized(); - // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor! - shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed(); + // NOTE: we don't take the scale of collision shapes into account when computing the inertia tensor! + shape_inertia_tensor = shape_basis * shape_inertia_tensor * shape_basis.transposed(); - Vector3 shape_origin = shape_transform.origin - center_of_mass_local; - inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass; - } + Vector3 shape_origin = shape_transform.origin - center_of_mass_local; + inertia_tensor += shape_inertia_tensor + (Basis() * shape_origin.dot(shape_origin) - shape_origin.outer(shape_origin)) * mass; + } - // Set the inertia to a valid value when there are no valid shapes. - if (!inertia_set) { - inertia_tensor.set_diagonal(Vector3(1.0, 1.0, 1.0)); - } + // Set the inertia to a valid value when there are no valid shapes. + if (!inertia_set) { + inertia_tensor = Basis(); + } - // Compute the principal axes of inertia. - principal_inertia_axes_local = inertia_tensor.diagonalize().transposed(); - _inv_inertia = inertia_tensor.get_main_diagonal().inverse(); + // Handle partial custom inertia. + if (inertia.x > 0.0) { + inertia_tensor[0][0] = inertia.x; + } + if (inertia.y > 0.0) { + inertia_tensor[1][1] = inertia.y; + } + if (inertia.z > 0.0) { + inertia_tensor[2][2] = inertia.z; + } + + // Compute the principal axes of inertia. + principal_inertia_axes_local = inertia_tensor.diagonalize().transposed(); + _inv_inertia = inertia_tensor.get_main_diagonal().inverse(); + } if (mass) { _inv_mass = 1.0 / mass; @@ -128,25 +149,28 @@ void Body3DSW::update_inertias() { } } break; - case PhysicsServer3D::BODY_MODE_KINEMATIC: case PhysicsServer3D::BODY_MODE_STATIC: { - _inv_inertia_tensor.set_zero(); + _inv_inertia = Vector3(); _inv_mass = 0; } break; - case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: { + case PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR: { _inv_inertia_tensor.set_zero(); _inv_mass = 1.0 / mass; } break; } - //_update_shapes(); + _update_transform_dependent(); +} - _update_transform_dependant(); +void GodotBody3D::reset_mass_properties() { + calculate_inertia = true; + calculate_center_of_mass = true; + _mass_properties_changed(); } -void Body3DSW::set_active(bool p_active) { +void GodotBody3D::set_active(bool p_active) { if (active == p_active) { return; } @@ -165,7 +189,7 @@ void Body3DSW::set_active(bool p_active) { } } -void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) { +void GodotBody3D::set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value) { switch (p_param) { case PhysicsServer3D::BODY_PARAM_BOUNCE: { bounce = p_value; @@ -174,14 +198,48 @@ void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) friction = p_value; } break; case PhysicsServer3D::BODY_PARAM_MASS: { - ERR_FAIL_COND(p_value <= 0); - mass = p_value; - _update_inertia(); - + real_t mass_value = p_value; + ERR_FAIL_COND(mass_value <= 0); + mass = mass_value; + if (mode >= PhysicsServer3D::BODY_MODE_DYNAMIC) { + _mass_properties_changed(); + } + } break; + case PhysicsServer3D::BODY_PARAM_INERTIA: { + inertia = p_value; + if ((inertia.x <= 0.0) || (inertia.y <= 0.0) || (inertia.z <= 0.0)) { + calculate_inertia = true; + if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) { + _mass_properties_changed(); + } + } else { + calculate_inertia = false; + if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) { + principal_inertia_axes_local = Basis(); + _inv_inertia = inertia.inverse(); + _update_transform_dependent(); + } + } + } break; + case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: { + calculate_center_of_mass = false; + center_of_mass_local = p_value; + _update_transform_dependent(); } break; case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: { + if (Math::is_zero_approx(gravity_scale)) { + wakeup(); + } gravity_scale = p_value; } break; + case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: { + int mode_value = p_value; + linear_damp_mode = (PhysicsServer3D::BodyDampMode)mode_value; + } break; + case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: { + int mode_value = p_value; + angular_damp_mode = (PhysicsServer3D::BodyDampMode)mode_value; + } break; case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: { linear_damp = p_value; } break; @@ -193,7 +251,7 @@ void Body3DSW::set_param(PhysicsServer3D::BodyParameter p_param, real_t p_value) } } -real_t Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const { +Variant GodotBody3D::get_param(PhysicsServer3D::BodyParameter p_param) const { switch (p_param) { case PhysicsServer3D::BODY_PARAM_BOUNCE: { return bounce; @@ -204,9 +262,25 @@ real_t Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const { case PhysicsServer3D::BODY_PARAM_MASS: { return mass; } break; + case PhysicsServer3D::BODY_PARAM_INERTIA: { + if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC) { + return _inv_inertia.inverse(); + } else { + return Vector3(); + } + } break; + case PhysicsServer3D::BODY_PARAM_CENTER_OF_MASS: { + return center_of_mass_local; + } break; case PhysicsServer3D::BODY_PARAM_GRAVITY_SCALE: { return gravity_scale; } break; + case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP_MODE: { + return linear_damp_mode; + } + case PhysicsServer3D::BODY_PARAM_ANGULAR_DAMP_MODE: { + return angular_damp_mode; + } case PhysicsServer3D::BODY_PARAM_LINEAR_DAMP: { return linear_damp; } break; @@ -221,56 +295,60 @@ real_t Body3DSW::get_param(PhysicsServer3D::BodyParameter p_param) const { return 0; } -void Body3DSW::set_mode(PhysicsServer3D::BodyMode p_mode) { +void GodotBody3D::set_mode(PhysicsServer3D::BodyMode p_mode) { PhysicsServer3D::BodyMode prev = mode; mode = p_mode; switch (p_mode) { - //CLEAR UP EVERYTHING IN CASE IT NOT WORKS! case PhysicsServer3D::BODY_MODE_STATIC: case PhysicsServer3D::BODY_MODE_KINEMATIC: { _set_inv_transform(get_transform().affine_inverse()); _inv_mass = 0; + _inv_inertia = Vector3(); _set_static(p_mode == PhysicsServer3D::BODY_MODE_STATIC); - //set_active(p_mode==PhysicsServer3D::BODY_MODE_KINEMATIC); set_active(p_mode == PhysicsServer3D::BODY_MODE_KINEMATIC && contacts.size()); linear_velocity = Vector3(); angular_velocity = Vector3(); if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC && prev != mode) { first_time_kinematic = true; } + _update_transform_dependent(); } break; case PhysicsServer3D::BODY_MODE_DYNAMIC: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; + if (!calculate_inertia) { + principal_inertia_axes_local = Basis(); + _inv_inertia = inertia.inverse(); + _update_transform_dependent(); + } + _mass_properties_changed(); _set_static(false); set_active(true); } break; - case PhysicsServer3D::BODY_MODE_DYNAMIC_LOCKED: { + case PhysicsServer3D::BODY_MODE_DYNAMIC_LINEAR: { _inv_mass = mass > 0 ? (1.0 / mass) : 0; + _inv_inertia = Vector3(); + angular_velocity = Vector3(); + _update_transform_dependent(); _set_static(false); set_active(true); - angular_velocity = Vector3(); - } break; + } } - - _update_inertia(); - /* - if (get_space()) - _update_queries(); - */ } -PhysicsServer3D::BodyMode Body3DSW::get_mode() const { +PhysicsServer3D::BodyMode GodotBody3D::get_mode() const { return mode; } -void Body3DSW::_shapes_changed() { - _update_inertia(); +void GodotBody3D::_shapes_changed() { + _mass_properties_changed(); + wakeup(); + wakeup_neighbours(); } -void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) { +void GodotBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) { switch (p_state) { case PhysicsServer3D::BODY_STATE_TRANSFORM: { if (mode == PhysicsServer3D::BODY_MODE_KINEMATIC) { @@ -296,16 +374,19 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va } _set_transform(t); _set_inv_transform(get_transform().inverse()); + _update_transform_dependent(); } wakeup(); } break; case PhysicsServer3D::BODY_STATE_LINEAR_VELOCITY: { linear_velocity = p_variant; + constant_linear_velocity = linear_velocity; wakeup(); } break; case PhysicsServer3D::BODY_STATE_ANGULAR_VELOCITY: { angular_velocity = p_variant; + constant_angular_velocity = angular_velocity; wakeup(); } break; @@ -326,7 +407,7 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va } break; case PhysicsServer3D::BODY_STATE_CAN_SLEEP: { can_sleep = p_variant; - if (mode == PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) { + if (mode >= PhysicsServer3D::BODY_MODE_DYNAMIC && !active && !can_sleep) { set_active(true); } @@ -334,7 +415,7 @@ void Body3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_va } } -Variant Body3DSW::get_state(PhysicsServer3D::BodyState p_state) const { +Variant GodotBody3D::get_state(PhysicsServer3D::BodyState p_state) const { switch (p_state) { case PhysicsServer3D::BODY_STATE_TRANSFORM: { return get_transform(); @@ -356,10 +437,10 @@ Variant Body3DSW::get_state(PhysicsServer3D::BodyState p_state) const { return Variant(); } -void Body3DSW::set_space(Space3DSW *p_space) { +void GodotBody3D::set_space(GodotSpace3D *p_space) { if (get_space()) { - if (inertia_update_list.in_list()) { - get_space()->body_remove_from_inertia_update_list(&inertia_update_list); + if (mass_properties_update_list.in_list()) { + get_space()->body_remove_from_mass_properties_update_list(&mass_properties_update_list); } if (active_list.in_list()) { get_space()->body_remove_from_active_list(&active_list); @@ -372,25 +453,14 @@ void Body3DSW::set_space(Space3DSW *p_space) { _set_space(p_space); if (get_space()) { - _update_inertia(); + _mass_properties_changed(); if (active) { get_space()->body_add_to_active_list(&active_list); } } - - first_integration = true; } -void Body3DSW::_compute_area_gravity_and_damping(const Area3DSW *p_area) { - Vector3 area_gravity; - p_area->compute_gravity(get_transform().get_origin(), area_gravity); - gravity += area_gravity; - - area_linear_damp += p_area->get_linear_damp(); - area_angular_damp += p_area->get_angular_damp(); -} - -void Body3DSW::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock) { +void GodotBody3D::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock) { if (lock) { locked_axis |= p_axis; } else { @@ -398,73 +468,141 @@ void Body3DSW::set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock) { } } -bool Body3DSW::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const { +bool GodotBody3D::is_axis_locked(PhysicsServer3D::BodyAxis p_axis) const { return locked_axis & p_axis; } -void Body3DSW::integrate_forces(real_t p_step) { +void GodotBody3D::integrate_forces(real_t p_step) { if (mode == PhysicsServer3D::BODY_MODE_STATIC) { return; } - Area3DSW *def_area = get_space()->get_default_area(); - // AreaSW *damp_area = def_area; - - ERR_FAIL_COND(!def_area); + ERR_FAIL_COND(!get_space()); int ac = areas.size(); + + bool gravity_done = false; + bool linear_damp_done = false; + bool angular_damp_done = false; + bool stopped = false; + gravity = Vector3(0, 0, 0); - area_linear_damp = 0; - area_angular_damp = 0; + + total_linear_damp = 0.0; + total_angular_damp = 0.0; + + // Combine gravity and damping from overlapping areas in priority order. if (ac) { areas.sort(); const AreaCMP *aa = &areas[0]; - // damp_area = aa[ac-1].area; for (int i = ac - 1; i >= 0 && !stopped; i--) { - PhysicsServer3D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode(); - switch (mode) { - case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: - case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { - _compute_area_gravity_and_damping(aa[i].area); - stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; - } break; - case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: - case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { - gravity = Vector3(0, 0, 0); - area_angular_damp = 0; - area_linear_damp = 0; - _compute_area_gravity_and_damping(aa[i].area); - stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; - } break; - default: { + if (!gravity_done) { + PhysicsServer3D::AreaSpaceOverrideMode area_gravity_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE); + if (area_gravity_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + Vector3 area_gravity; + aa[i].area->compute_gravity(get_transform().get_origin(), area_gravity); + switch (area_gravity_mode) { + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + gravity += area_gravity; + gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + gravity = area_gravity; + gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } + } + } + if (!linear_damp_done) { + PhysicsServer3D::AreaSpaceOverrideMode area_linear_damp_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE); + if (area_linear_damp_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + real_t area_linear_damp = aa[i].area->get_linear_damp(); + switch (area_linear_damp_mode) { + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + total_linear_damp += area_linear_damp; + linear_damp_done = area_linear_damp_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + total_linear_damp = area_linear_damp; + linear_damp_done = area_linear_damp_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } + } + } + if (!angular_damp_done) { + PhysicsServer3D::AreaSpaceOverrideMode area_angular_damp_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE); + if (area_angular_damp_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + real_t area_angular_damp = aa[i].area->get_angular_damp(); + switch (area_angular_damp_mode) { + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + total_angular_damp += area_angular_damp; + angular_damp_done = area_angular_damp_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + total_angular_damp = area_angular_damp; + angular_damp_done = area_angular_damp_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } } } + stopped = gravity_done && linear_damp_done && angular_damp_done; } } + // Add default gravity and damping from space area. if (!stopped) { - _compute_area_gravity_and_damping(def_area); - } + GodotArea3D *default_area = get_space()->get_default_area(); + ERR_FAIL_COND(!default_area); - gravity *= gravity_scale; + if (!gravity_done) { + Vector3 default_gravity; + default_area->compute_gravity(get_transform().get_origin(), default_gravity); + gravity += default_gravity; + } + + if (!linear_damp_done) { + total_linear_damp += default_area->get_linear_damp(); + } - // If less than 0, override dampenings with that of the Body - if (angular_damp >= 0) { - area_angular_damp = angular_damp; + if (!angular_damp_done) { + total_angular_damp += default_area->get_angular_damp(); + } + } + + // Override linear damping with body's value. + switch (linear_damp_mode) { + case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: { + total_linear_damp += linear_damp; + } break; + case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: { + total_linear_damp = linear_damp; + } break; } - /* - else - area_angular_damp=damp_area->get_angular_damp(); - */ - if (linear_damp >= 0) { - area_linear_damp = linear_damp; + // Override angular damping with body's value. + switch (angular_damp_mode) { + case PhysicsServer3D::BODY_DAMP_MODE_COMBINE: { + total_angular_damp += angular_damp; + } break; + case PhysicsServer3D::BODY_DAMP_MODE_REPLACE: { + total_angular_damp = angular_damp; + } break; } - /* - else - area_linear_damp=damp_area->get_linear_damp(); - */ + + gravity *= gravity_scale; Vector3 motion; bool do_motion = false; @@ -473,7 +611,7 @@ void Body3DSW::integrate_forces(real_t p_step) { //compute motion, angular and etc. velocities from prev transform motion = new_transform.origin - get_transform().origin; do_motion = true; - linear_velocity = motion / p_step; + linear_velocity = constant_linear_velocity + motion / p_step; //compute a FAKE angular velocity, not so easy Basis rot = new_transform.basis.orthonormalized() * get_transform().basis.orthonormalized().transposed(); @@ -482,22 +620,22 @@ void Body3DSW::integrate_forces(real_t p_step) { rot.get_axis_angle(axis, angle); axis.normalize(); - angular_velocity = axis * (angle / p_step); + angular_velocity = constant_angular_velocity + axis * (angle / p_step); } else { - if (!omit_force_integration && !first_integration) { + if (!omit_force_integration) { //overridden by direct state query Vector3 force = gravity * mass; force += applied_force; Vector3 torque = applied_torque; - real_t damp = 1.0 - p_step * area_linear_damp; + real_t damp = 1.0 - p_step * total_linear_damp; if (damp < 0) { // reached zero in the given time damp = 0; } - real_t angular_damp = 1.0 - p_step * area_angular_damp; + real_t angular_damp = 1.0 - p_step * total_angular_damp; if (angular_damp < 0) { // reached zero in the given time angular_damp = 0; @@ -518,9 +656,6 @@ void Body3DSW::integrate_forces(real_t p_step) { applied_force = Vector3(); applied_torque = Vector3(); - first_integration = false; - - //motion=linear_velocity*p_step; biased_angular_velocity = Vector3(); biased_linear_velocity = Vector3(); @@ -529,11 +664,10 @@ void Body3DSW::integrate_forces(real_t p_step) { _update_shapes_with_motion(motion); } - def_area = nullptr; // clear the area, so it is set in the next frame contact_count = 0; } -void Body3DSW::integrate_velocities(real_t p_step) { +void GodotBody3D::integrate_velocities(real_t p_step) { if (mode == PhysicsServer3D::BODY_MODE_STATIC) { return; } @@ -594,53 +728,21 @@ void Body3DSW::integrate_velocities(real_t p_step) { _set_transform(transform); _set_inv_transform(get_transform().inverse()); - _update_transform_dependant(); -} - -/* -void BodySW::simulate_motion(const Transform3D& p_xform,real_t p_step) { - Transform3D inv_xform = p_xform.affine_inverse(); - if (!get_space()) { - _set_transform(p_xform); - _set_inv_transform(inv_xform); - - return; - } - - //compute a FAKE linear velocity - this is easy - - linear_velocity=(p_xform.origin - get_transform().origin)/p_step; - - //compute a FAKE angular velocity, not so easy - Basis rot=get_transform().basis.orthonormalized().transposed() * p_xform.basis.orthonormalized(); - Vector3 axis; - real_t angle; - - rot.get_axis_angle(axis,angle); - axis.normalize(); - angular_velocity=axis.normalized() * (angle/p_step); - linear_velocity = (p_xform.origin - get_transform().origin)/p_step; - - if (!direct_state_query_list.in_list())// - callalways, so lv and av are cleared && (state_query || direct_state_query)) - get_space()->body_add_to_state_query_list(&direct_state_query_list); - simulated_motion=true; - _set_transform(p_xform); + _update_transform_dependent(); } -*/ - -void Body3DSW::wakeup_neighbours() { - for (Map<Constraint3DSW *, int>::Element *E = constraint_map.front(); E; E = E->next()) { - const Constraint3DSW *c = E->key(); - Body3DSW **n = c->get_body_ptr(); +void GodotBody3D::wakeup_neighbours() { + for (const KeyValue<GodotConstraint3D *, int> &E : constraint_map) { + const GodotConstraint3D *c = E.key; + GodotBody3D **n = c->get_body_ptr(); int bc = c->get_body_count(); for (int i = 0; i < bc; i++) { - if (i == E->get()) { + if (i == E.value) { continue; } - Body3DSW *b = n[i]; - if (b->mode != PhysicsServer3D::BODY_MODE_DYNAMIC) { + GodotBody3D *b = n[i]; + if (b->mode < PhysicsServer3D::BODY_MODE_DYNAMIC) { continue; } @@ -651,7 +753,7 @@ void Body3DSW::wakeup_neighbours() { } } -void Body3DSW::call_queries() { +void GodotBody3D::call_queries() { if (fi_callback_data) { if (!fi_callback_data->callable.get_object()) { set_force_integration_callback(Callable()); @@ -671,7 +773,7 @@ void Body3DSW::call_queries() { } } -bool Body3DSW::sleep_test(real_t p_step) { +bool GodotBody3D::sleep_test(real_t p_step) { if (mode == PhysicsServer3D::BODY_MODE_STATIC || mode == PhysicsServer3D::BODY_MODE_KINEMATIC) { return true; } else if (!can_sleep) { @@ -688,12 +790,12 @@ bool Body3DSW::sleep_test(real_t p_step) { } } -void Body3DSW::set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback) { +void GodotBody3D::set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback) { body_state_callback_instance = p_instance; body_state_callback = p_callback; } -void Body3DSW::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { +void GodotBody3D::set_force_integration_callback(const Callable &p_callable, const Variant &p_udata) { if (p_callable.get_object()) { if (!fi_callback_data) { fi_callback_data = memnew(ForceIntegrationCallbackData); @@ -706,46 +808,23 @@ void Body3DSW::set_force_integration_callback(const Callable &p_callable, const } } -PhysicsDirectBodyState3DSW *Body3DSW::get_direct_state() { +GodotPhysicsDirectBodyState3D *GodotBody3D::get_direct_state() { if (!direct_state) { - direct_state = memnew(PhysicsDirectBodyState3DSW); + direct_state = memnew(GodotPhysicsDirectBodyState3D); direct_state->body = this; } return direct_state; } -Body3DSW::Body3DSW() : - CollisionObject3DSW(TYPE_BODY), +GodotBody3D::GodotBody3D() : + GodotCollisionObject3D(TYPE_BODY), active_list(this), - inertia_update_list(this), + mass_properties_update_list(this), direct_state_query_list(this) { - mode = PhysicsServer3D::BODY_MODE_DYNAMIC; - active = true; - - mass = 1; - _inv_mass = 1; - bounce = 0; - friction = 1; - omit_force_integration = false; - //applied_torque=0; - island_step = 0; - first_time_kinematic = false; - first_integration = false; _set_static(false); - - contact_count = 0; - gravity_scale = 1.0; - linear_damp = -1; - angular_damp = -1; - area_angular_damp = 0; - area_linear_damp = 0; - - still_time = 0; - continuous_cd = false; - can_sleep = true; } -Body3DSW::~Body3DSW() { +GodotBody3D::~GodotBody3D() { if (fi_callback_data) { memdelete(fi_callback_data); } diff --git a/servers/physics_3d/body_3d_sw.h b/servers/physics_3d/godot_body_3d.h index f58f40652b..bba9ec6c3a 100644 --- a/servers/physics_3d/body_3d_sw.h +++ b/servers/physics_3d/godot_body_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_3d_sw.h */ +/* godot_body_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,35 +28,47 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BODY_3D_SW_H -#define BODY_3D_SW_H +#ifndef GODOT_BODY_3D_H +#define GODOT_BODY_3D_H + +#include "godot_area_3d.h" +#include "godot_collision_object_3d.h" -#include "area_3d_sw.h" -#include "collision_object_3d_sw.h" #include "core/templates/vset.h" -class Constraint3DSW; -class PhysicsDirectBodyState3DSW; +class GodotConstraint3D; +class GodotPhysicsDirectBodyState3D; -class Body3DSW : public CollisionObject3DSW { - PhysicsServer3D::BodyMode mode; +class GodotBody3D : public GodotCollisionObject3D { + PhysicsServer3D::BodyMode mode = PhysicsServer3D::BODY_MODE_DYNAMIC; Vector3 linear_velocity; Vector3 angular_velocity; + Vector3 constant_linear_velocity; + Vector3 constant_angular_velocity; + Vector3 biased_linear_velocity; Vector3 biased_angular_velocity; - real_t mass; - real_t bounce; - real_t friction; + real_t mass = 1.0; + real_t bounce = 0.0; + real_t friction = 1.0; + Vector3 inertia; + + PhysicsServer3D::BodyDampMode linear_damp_mode = PhysicsServer3D::BODY_DAMP_MODE_COMBINE; + PhysicsServer3D::BodyDampMode angular_damp_mode = PhysicsServer3D::BODY_DAMP_MODE_COMBINE; + + real_t linear_damp = 0.0; + real_t angular_damp = 0.0; - real_t linear_damp; - real_t angular_damp; - real_t gravity_scale; + real_t total_linear_damp = 0.0; + real_t total_angular_damp = 0.0; + + real_t gravity_scale = 1.0; uint16_t locked_axis = 0; - real_t _inv_mass; + real_t _inv_mass = 1.0; Vector3 _inv_inertia; // Relative to the principal axes of inertia // Relative to the local frame of reference @@ -68,51 +80,50 @@ class Body3DSW : public CollisionObject3DSW { Basis principal_inertia_axes; Vector3 center_of_mass; + bool calculate_inertia = true; + bool calculate_center_of_mass = true; + Vector3 gravity; - real_t still_time; + real_t still_time = 0.0; Vector3 applied_force; Vector3 applied_torque; - real_t area_angular_damp; - real_t area_linear_damp; - - SelfList<Body3DSW> active_list; - SelfList<Body3DSW> inertia_update_list; - SelfList<Body3DSW> direct_state_query_list; + SelfList<GodotBody3D> active_list; + SelfList<GodotBody3D> mass_properties_update_list; + SelfList<GodotBody3D> direct_state_query_list; VSet<RID> exceptions; - bool omit_force_integration; - bool active; + bool omit_force_integration = false; + bool active = true; - bool first_integration; + bool continuous_cd = false; + bool can_sleep = true; + bool first_time_kinematic = false; - bool continuous_cd; - bool can_sleep; - bool first_time_kinematic; - void _update_inertia(); + void _mass_properties_changed(); virtual void _shapes_changed(); Transform3D new_transform; - Map<Constraint3DSW *, int> constraint_map; + Map<GodotConstraint3D *, int> constraint_map; Vector<AreaCMP> areas; struct Contact { Vector3 local_pos; Vector3 local_normal; - real_t depth; - int local_shape; + real_t depth = 0.0; + int local_shape = 0; Vector3 collider_pos; - int collider_shape; + int collider_shape = 0; ObjectID collider_instance_id; RID collider; Vector3 collider_velocity_at_pos; }; Vector<Contact> contacts; //no contacts by default - int contact_count; + int contact_count = 0; void *body_state_callback_instance = nullptr; PhysicsServer3D::BodyStateCallback body_state_callback = nullptr; @@ -124,23 +135,21 @@ class Body3DSW : public CollisionObject3DSW { ForceIntegrationCallbackData *fi_callback_data = nullptr; - PhysicsDirectBodyState3DSW *direct_state = nullptr; - - uint64_t island_step; + GodotPhysicsDirectBodyState3D *direct_state = nullptr; - _FORCE_INLINE_ void _compute_area_gravity_and_damping(const Area3DSW *p_area); + uint64_t island_step = 0; - _FORCE_INLINE_ void _update_transform_dependant(); + void _update_transform_dependent(); - friend class PhysicsDirectBodyState3DSW; // i give up, too many functions to expose + friend class GodotPhysicsDirectBodyState3D; // i give up, too many functions to expose public: void set_state_sync_callback(void *p_instance, PhysicsServer3D::BodyStateCallback p_callback); void set_force_integration_callback(const Callable &p_callable, const Variant &p_udata = Variant()); - PhysicsDirectBodyState3DSW *get_direct_state(); + GodotPhysicsDirectBodyState3D *get_direct_state(); - _FORCE_INLINE_ void add_area(Area3DSW *p_area) { + _FORCE_INLINE_ void add_area(GodotArea3D *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { areas.write[index].refCount += 1; @@ -149,12 +158,12 @@ public: } } - _FORCE_INLINE_ void remove_area(Area3DSW *p_area) { + _FORCE_INLINE_ void remove_area(GodotArea3D *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { areas.write[index].refCount -= 1; if (areas[index].refCount < 1) { - areas.remove(index); + areas.remove_at(index); } } } @@ -179,9 +188,9 @@ public: _FORCE_INLINE_ uint64_t get_island_step() const { return island_step; } _FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; } - _FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; } - _FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraint_map.erase(p_constraint); } - const Map<Constraint3DSW *, int> &get_constraint_map() const { return constraint_map; } + _FORCE_INLINE_ void add_constraint(GodotConstraint3D *p_constraint, int p_pos) { constraint_map[p_constraint] = p_pos; } + _FORCE_INLINE_ void remove_constraint(GodotConstraint3D *p_constraint) { constraint_map.erase(p_constraint); } + const Map<GodotConstraint3D *, int> &get_constraint_map() const { return constraint_map; } _FORCE_INLINE_ void clear_constraint_map() { constraint_map.clear(); } _FORCE_INLINE_ void set_omit_force_integration(bool p_omit_force_integration) { omit_force_integration = p_omit_force_integration; } @@ -189,6 +198,7 @@ public: _FORCE_INLINE_ Basis get_principal_inertia_axes() const { return principal_inertia_axes; } _FORCE_INLINE_ Vector3 get_center_of_mass() const { return center_of_mass; } + _FORCE_INLINE_ Vector3 get_center_of_mass_local() const { return center_of_mass_local; } _FORCE_INLINE_ Vector3 xform_local_to_principal(const Vector3 &p_pos) const { return principal_inertia_axes_local.xform(p_pos - center_of_mass_local); } _FORCE_INLINE_ void set_linear_velocity(const Vector3 &p_velocity) { linear_velocity = p_velocity; } @@ -251,8 +261,8 @@ public: set_active(true); } - void set_param(PhysicsServer3D::BodyParameter p_param, real_t); - real_t get_param(PhysicsServer3D::BodyParameter p_param) const; + void set_param(PhysicsServer3D::BodyParameter p_param, const Variant &p_value); + Variant get_param(PhysicsServer3D::BodyParameter p_param) const; void set_mode(PhysicsServer3D::BodyMode p_mode); PhysicsServer3D::BodyMode get_mode() const; @@ -269,15 +279,15 @@ public: _FORCE_INLINE_ void set_continuous_collision_detection(bool p_enable) { continuous_cd = p_enable; } _FORCE_INLINE_ bool is_continuous_collision_detection_enabled() const { return continuous_cd; } - void set_space(Space3DSW *p_space); + void set_space(GodotSpace3D *p_space); - void update_inertias(); + void update_mass_properties(); + void reset_mass_properties(); _FORCE_INLINE_ real_t get_inv_mass() const { return _inv_mass; } _FORCE_INLINE_ const Vector3 &get_inv_inertia() const { return _inv_inertia; } _FORCE_INLINE_ const Basis &get_inv_inertia_tensor() const { return _inv_inertia_tensor; } _FORCE_INLINE_ real_t get_friction() const { return friction; } - _FORCE_INLINE_ const Vector3 &get_gravity() const { return gravity; } _FORCE_INLINE_ real_t get_bounce() const { return bounce; } void set_axis_lock(PhysicsServer3D::BodyAxis p_axis, bool lock); @@ -310,13 +320,13 @@ public: bool sleep_test(real_t p_step); - Body3DSW(); - ~Body3DSW(); + GodotBody3D(); + ~GodotBody3D(); }; //add contact inline -void Body3DSW::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos) { +void GodotBody3D::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_normal, real_t p_depth, int p_local_shape, const Vector3 &p_collider_pos, int p_collider_shape, ObjectID p_collider_instance_id, const RID &p_collider, const Vector3 &p_collider_velocity_at_pos) { int c_max = contacts.size(); if (c_max == 0) { @@ -358,4 +368,4 @@ void Body3DSW::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_no c[idx].collider_velocity_at_pos = p_collider_velocity_at_pos; } -#endif // BODY_3D_SW_H +#endif // GODOT_BODY_3D_H diff --git a/servers/physics_3d/body_direct_state_3d_sw.cpp b/servers/physics_3d/godot_body_direct_state_3d.cpp index d197dd288d..a929cab6f9 100644 --- a/servers/physics_3d/body_direct_state_3d_sw.cpp +++ b/servers/physics_3d/godot_body_direct_state_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_direct_state_3d_sw.cpp */ +/* godot_body_direct_state_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,155 +28,167 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "body_direct_state_3d_sw.h" +#include "godot_body_direct_state_3d.h" -#include "body_3d_sw.h" -#include "space_3d_sw.h" +#include "godot_body_3d.h" +#include "godot_space_3d.h" -Vector3 PhysicsDirectBodyState3DSW::get_total_gravity() const { +Vector3 GodotPhysicsDirectBodyState3D::get_total_gravity() const { return body->gravity; } -real_t PhysicsDirectBodyState3DSW::get_total_angular_damp() const { - return body->area_angular_damp; +real_t GodotPhysicsDirectBodyState3D::get_total_angular_damp() const { + return body->total_angular_damp; } -real_t PhysicsDirectBodyState3DSW::get_total_linear_damp() const { - return body->area_linear_damp; +real_t GodotPhysicsDirectBodyState3D::get_total_linear_damp() const { + return body->total_linear_damp; } -Vector3 PhysicsDirectBodyState3DSW::get_center_of_mass() const { +Vector3 GodotPhysicsDirectBodyState3D::get_center_of_mass() const { return body->get_center_of_mass(); } -Basis PhysicsDirectBodyState3DSW::get_principal_inertia_axes() const { +Vector3 GodotPhysicsDirectBodyState3D::get_center_of_mass_local() const { + return body->get_center_of_mass_local(); +} + +Basis GodotPhysicsDirectBodyState3D::get_principal_inertia_axes() const { return body->get_principal_inertia_axes(); } -real_t PhysicsDirectBodyState3DSW::get_inverse_mass() const { +real_t GodotPhysicsDirectBodyState3D::get_inverse_mass() const { return body->get_inv_mass(); } -Vector3 PhysicsDirectBodyState3DSW::get_inverse_inertia() const { +Vector3 GodotPhysicsDirectBodyState3D::get_inverse_inertia() const { return body->get_inv_inertia(); } -Basis PhysicsDirectBodyState3DSW::get_inverse_inertia_tensor() const { +Basis GodotPhysicsDirectBodyState3D::get_inverse_inertia_tensor() const { return body->get_inv_inertia_tensor(); } -void PhysicsDirectBodyState3DSW::set_linear_velocity(const Vector3 &p_velocity) { +void GodotPhysicsDirectBodyState3D::set_linear_velocity(const Vector3 &p_velocity) { + body->wakeup(); body->set_linear_velocity(p_velocity); } -Vector3 PhysicsDirectBodyState3DSW::get_linear_velocity() const { +Vector3 GodotPhysicsDirectBodyState3D::get_linear_velocity() const { return body->get_linear_velocity(); } -void PhysicsDirectBodyState3DSW::set_angular_velocity(const Vector3 &p_velocity) { +void GodotPhysicsDirectBodyState3D::set_angular_velocity(const Vector3 &p_velocity) { + body->wakeup(); body->set_angular_velocity(p_velocity); } -Vector3 PhysicsDirectBodyState3DSW::get_angular_velocity() const { +Vector3 GodotPhysicsDirectBodyState3D::get_angular_velocity() const { return body->get_angular_velocity(); } -void PhysicsDirectBodyState3DSW::set_transform(const Transform3D &p_transform) { +void GodotPhysicsDirectBodyState3D::set_transform(const Transform3D &p_transform) { body->set_state(PhysicsServer3D::BODY_STATE_TRANSFORM, p_transform); } -Transform3D PhysicsDirectBodyState3DSW::get_transform() const { +Transform3D GodotPhysicsDirectBodyState3D::get_transform() const { return body->get_transform(); } -Vector3 PhysicsDirectBodyState3DSW::get_velocity_at_local_position(const Vector3 &p_position) const { +Vector3 GodotPhysicsDirectBodyState3D::get_velocity_at_local_position(const Vector3 &p_position) const { return body->get_velocity_in_local_point(p_position); } -void PhysicsDirectBodyState3DSW::add_central_force(const Vector3 &p_force) { +void GodotPhysicsDirectBodyState3D::add_central_force(const Vector3 &p_force) { + body->wakeup(); body->add_central_force(p_force); } -void PhysicsDirectBodyState3DSW::add_force(const Vector3 &p_force, const Vector3 &p_position) { +void GodotPhysicsDirectBodyState3D::add_force(const Vector3 &p_force, const Vector3 &p_position) { + body->wakeup(); body->add_force(p_force, p_position); } -void PhysicsDirectBodyState3DSW::add_torque(const Vector3 &p_torque) { +void GodotPhysicsDirectBodyState3D::add_torque(const Vector3 &p_torque) { + body->wakeup(); body->add_torque(p_torque); } -void PhysicsDirectBodyState3DSW::apply_central_impulse(const Vector3 &p_impulse) { +void GodotPhysicsDirectBodyState3D::apply_central_impulse(const Vector3 &p_impulse) { + body->wakeup(); body->apply_central_impulse(p_impulse); } -void PhysicsDirectBodyState3DSW::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { +void GodotPhysicsDirectBodyState3D::apply_impulse(const Vector3 &p_impulse, const Vector3 &p_position) { + body->wakeup(); body->apply_impulse(p_impulse, p_position); } -void PhysicsDirectBodyState3DSW::apply_torque_impulse(const Vector3 &p_impulse) { +void GodotPhysicsDirectBodyState3D::apply_torque_impulse(const Vector3 &p_impulse) { + body->wakeup(); body->apply_torque_impulse(p_impulse); } -void PhysicsDirectBodyState3DSW::set_sleep_state(bool p_sleep) { +void GodotPhysicsDirectBodyState3D::set_sleep_state(bool p_sleep) { body->set_active(!p_sleep); } -bool PhysicsDirectBodyState3DSW::is_sleeping() const { +bool GodotPhysicsDirectBodyState3D::is_sleeping() const { return !body->is_active(); } -int PhysicsDirectBodyState3DSW::get_contact_count() const { +int GodotPhysicsDirectBodyState3D::get_contact_count() const { return body->contact_count; } -Vector3 PhysicsDirectBodyState3DSW::get_contact_local_position(int p_contact_idx) const { +Vector3 GodotPhysicsDirectBodyState3D::get_contact_local_position(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3()); return body->contacts[p_contact_idx].local_pos; } -Vector3 PhysicsDirectBodyState3DSW::get_contact_local_normal(int p_contact_idx) const { +Vector3 GodotPhysicsDirectBodyState3D::get_contact_local_normal(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3()); return body->contacts[p_contact_idx].local_normal; } -real_t PhysicsDirectBodyState3DSW::get_contact_impulse(int p_contact_idx) const { +real_t GodotPhysicsDirectBodyState3D::get_contact_impulse(int p_contact_idx) const { return 0.0f; // Only implemented for bullet } -int PhysicsDirectBodyState3DSW::get_contact_local_shape(int p_contact_idx) const { +int GodotPhysicsDirectBodyState3D::get_contact_local_shape(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1); return body->contacts[p_contact_idx].local_shape; } -RID PhysicsDirectBodyState3DSW::get_contact_collider(int p_contact_idx) const { +RID GodotPhysicsDirectBodyState3D::get_contact_collider(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, RID()); return body->contacts[p_contact_idx].collider; } -Vector3 PhysicsDirectBodyState3DSW::get_contact_collider_position(int p_contact_idx) const { +Vector3 GodotPhysicsDirectBodyState3D::get_contact_collider_position(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3()); return body->contacts[p_contact_idx].collider_pos; } -ObjectID PhysicsDirectBodyState3DSW::get_contact_collider_id(int p_contact_idx) const { +ObjectID GodotPhysicsDirectBodyState3D::get_contact_collider_id(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, ObjectID()); return body->contacts[p_contact_idx].collider_instance_id; } -int PhysicsDirectBodyState3DSW::get_contact_collider_shape(int p_contact_idx) const { +int GodotPhysicsDirectBodyState3D::get_contact_collider_shape(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, 0); return body->contacts[p_contact_idx].collider_shape; } -Vector3 PhysicsDirectBodyState3DSW::get_contact_collider_velocity_at_position(int p_contact_idx) const { +Vector3 GodotPhysicsDirectBodyState3D::get_contact_collider_velocity_at_position(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3()); return body->contacts[p_contact_idx].collider_velocity_at_pos; } -PhysicsDirectSpaceState3D *PhysicsDirectBodyState3DSW::get_space_state() { +PhysicsDirectSpaceState3D *GodotPhysicsDirectBodyState3D::get_space_state() { return body->get_space()->get_direct_state(); } -real_t PhysicsDirectBodyState3DSW::get_step() const { +real_t GodotPhysicsDirectBodyState3D::get_step() const { return body->get_space()->get_last_step(); } diff --git a/servers/physics_3d/body_direct_state_3d_sw.h b/servers/physics_3d/godot_body_direct_state_3d.h index 5132376715..35fd1543b0 100644 --- a/servers/physics_3d/body_direct_state_3d_sw.h +++ b/servers/physics_3d/godot_body_direct_state_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_direct_state_3d_sw.h */ +/* godot_body_direct_state_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,24 +28,25 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BODY_DIRECT_STATE_3D_SW_H -#define BODY_DIRECT_STATE_3D_SW_H +#ifndef GODOT_BODY_DIRECT_STATE_3D_H +#define GODOT_BODY_DIRECT_STATE_3D_H #include "servers/physics_server_3d.h" -class Body3DSW; +class GodotBody3D; -class PhysicsDirectBodyState3DSW : public PhysicsDirectBodyState3D { - GDCLASS(PhysicsDirectBodyState3DSW, PhysicsDirectBodyState3D); +class GodotPhysicsDirectBodyState3D : public PhysicsDirectBodyState3D { + GDCLASS(GodotPhysicsDirectBodyState3D, PhysicsDirectBodyState3D); public: - Body3DSW *body = nullptr; + GodotBody3D *body = nullptr; virtual Vector3 get_total_gravity() const override; virtual real_t get_total_angular_damp() const override; virtual real_t get_total_linear_damp() const override; virtual Vector3 get_center_of_mass() const override; + virtual Vector3 get_center_of_mass_local() const override; virtual Basis get_principal_inertia_axes() const override; virtual real_t get_inverse_mass() const override; @@ -91,4 +92,4 @@ public: virtual real_t get_step() const override; }; -#endif // BODY_DIRECT_STATE_3D_SW_H +#endif // GODOT_BODY_DIRECT_STATE_3D_H diff --git a/servers/physics_3d/body_pair_3d_sw.cpp b/servers/physics_3d/godot_body_pair_3d.cpp index c27a2ecced..f0002870ae 100644 --- a/servers/physics_3d/body_pair_3d_sw.cpp +++ b/servers/physics_3d/godot_body_pair_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_pair_3d_sw.cpp */ +/* godot_body_pair_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "body_pair_3d_sw.h" +#include "godot_body_pair_3d.h" + +#include "godot_collision_solver_3d.h" +#include "godot_space_3d.h" -#include "collision_solver_3d_sw.h" #include "core/os/os.h" -#include "space_3d_sw.h" /* #define NO_ACCUMULATE_IMPULSES @@ -49,12 +50,12 @@ #define MIN_VELOCITY 0.0001 #define MAX_BIAS_ROTATION (Math_PI / 8) -void BodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { - BodyPair3DSW *pair = (BodyPair3DSW *)p_userdata; +void GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { + GodotBodyPair3D *pair = (GodotBodyPair3D *)p_userdata; pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B); } -void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { +void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { // check if we already have the contact //Vector3 local_A = A->get_inv_transform().xform(p_point_A); @@ -135,7 +136,7 @@ void BodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_ } } -void BodyPair3DSW::validate_contacts() { +void GodotBodyPair3D::validate_contacts() { //make sure to erase contacts that are no longer valid real_t contact_max_separation = space->get_contact_max_separation(); @@ -161,7 +162,7 @@ void BodyPair3DSW::validate_contacts() { } } -bool BodyPair3DSW::_test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform3D &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform3D &p_xform_B) { +bool GodotBodyPair3D::_test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A, const Transform3D &p_xform_A, GodotBody3D *p_B, int p_shape_B, const Transform3D &p_xform_B) { Vector3 motion = p_A->get_linear_velocity() * p_step; real_t mlen = motion.length(); if (mlen < CMP_EPSILON) { @@ -190,7 +191,7 @@ bool BodyPair3DSW::_test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Vector3 local_to = from_inv.xform(to); Vector3 rpos, rnorm; - if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from, local_to, rpos, rnorm)) { + if (!p_B->get_shape(p_shape_B)->intersect_segment(local_from, local_to, rpos, rnorm, true)) { return false; } @@ -203,15 +204,15 @@ bool BodyPair3DSW::_test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const return true; } -real_t combine_bounce(Body3DSW *A, Body3DSW *B) { +real_t combine_bounce(GodotBody3D *A, GodotBody3D *B) { return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1); } -real_t combine_friction(Body3DSW *A, Body3DSW *B) { +real_t combine_friction(GodotBody3D *A, GodotBody3D *B) { return ABS(MIN(A->get_friction(), B->get_friction())); } -bool BodyPair3DSW::setup(real_t p_step) { +bool GodotBodyPair3D::setup(real_t p_step) { if (!A->interacts_with(B) || A->has_exception(B->get_self()) || B->has_exception(A->get_self())) { collided = false; return false; @@ -242,10 +243,10 @@ bool BodyPair3DSW::setup(real_t p_step) { xform_Bu.origin -= offset_A; Transform3D xform_B = xform_Bu * B->get_shape_transform(shape_B); - Shape3DSW *shape_A_ptr = A->get_shape(shape_A); - Shape3DSW *shape_B_ptr = B->get_shape(shape_B); + GodotShape3D *shape_A_ptr = A->get_shape(shape_A); + GodotShape3D *shape_B_ptr = B->get_shape(shape_B); - collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis); + collided = GodotCollisionSolver3D::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis); if (!collided) { //test ccd (currently just a raycast) @@ -264,7 +265,7 @@ bool BodyPair3DSW::setup(real_t p_step) { return true; } -bool BodyPair3DSW::pre_solve(real_t p_step) { +bool GodotBodyPair3D::pre_solve(real_t p_step) { if (!collided) { return false; } @@ -273,8 +274,8 @@ bool BodyPair3DSW::pre_solve(real_t p_step) { real_t bias = (real_t)0.3; - Shape3DSW *shape_A_ptr = A->get_shape(shape_A); - Shape3DSW *shape_B_ptr = B->get_shape(shape_B); + GodotShape3D *shape_A_ptr = A->get_shape(shape_A); + GodotShape3D *shape_B_ptr = B->get_shape(shape_B); if (shape_A_ptr->get_custom_bias() || shape_B_ptr->get_custom_bias()) { if (shape_A_ptr->get_custom_bias() == 0) { @@ -380,7 +381,7 @@ bool BodyPair3DSW::pre_solve(real_t p_step) { return do_process; } -void BodyPair3DSW::solve(real_t p_step) { +void GodotBodyPair3D::solve(real_t p_step) { if (!collided) { return; } @@ -494,8 +495,7 @@ void BodyPair3DSW::solve(real_t p_step) { Vector3 temp1 = inv_inertia_tensor_A.xform(c.rA.cross(tv)); Vector3 temp2 = inv_inertia_tensor_B.xform(c.rB.cross(tv)); - real_t t = -tvl / - (inv_mass_A + inv_mass_B + tv.dot(temp1.cross(c.rA) + temp2.cross(c.rB))); + real_t t = -tvl / (inv_mass_A + inv_mass_B + tv.dot(temp1.cross(c.rA) + temp2.cross(c.rB))); Vector3 jt = t * tv; @@ -523,8 +523,8 @@ void BodyPair3DSW::solve(real_t p_step) { } } -BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B) : - BodyContact3DSW(_arr, 2) { +GodotBodyPair3D::GodotBodyPair3D(GodotBody3D *p_A, int p_shape_A, GodotBody3D *p_B, int p_shape_B) : + GodotBodyContact3D(_arr, 2) { A = p_A; B = p_B; shape_A = p_shape_A; @@ -534,17 +534,17 @@ BodyPair3DSW::BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_sh B->add_constraint(this, 1); } -BodyPair3DSW::~BodyPair3DSW() { +GodotBodyPair3D::~GodotBodyPair3D() { A->remove_constraint(this); B->remove_constraint(this); } -void BodySoftBodyPair3DSW::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { - BodySoftBodyPair3DSW *pair = (BodySoftBodyPair3DSW *)p_userdata; +void GodotBodySoftBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { + GodotBodySoftBodyPair3D *pair = (GodotBodySoftBodyPair3D *)p_userdata; pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B); } -void BodySoftBodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { +void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) { Vector3 local_A = body->get_inv_transform().xform(p_point_A); Vector3 local_B = p_point_B - soft_body->get_node_position(p_index_B); @@ -582,7 +582,7 @@ void BodySoftBodyPair3DSW::contact_added_callback(const Vector3 &p_point_A, int contacts.push_back(contact); } -void BodySoftBodyPair3DSW::validate_contacts() { +void GodotBodySoftBodyPair3D::validate_contacts() { // Make sure to erase contacts that are no longer valid. const Transform3D &transform_A = body->get_transform(); @@ -612,7 +612,7 @@ void BodySoftBodyPair3DSW::validate_contacts() { contacts.resize(contact_count); } -bool BodySoftBodyPair3DSW::setup(real_t p_step) { +bool GodotBodySoftBodyPair3D::setup(real_t p_step) { if (!body->interacts_with(soft_body) || body->has_exception(soft_body->get_self()) || soft_body->has_exception(body->get_self())) { collided = false; return false; @@ -638,15 +638,15 @@ bool BodySoftBodyPair3DSW::setup(real_t p_step) { validate_contacts(); - Shape3DSW *shape_A_ptr = body->get_shape(body_shape); - Shape3DSW *shape_B_ptr = soft_body->get_shape(0); + GodotShape3D *shape_A_ptr = body->get_shape(body_shape); + GodotShape3D *shape_B_ptr = soft_body->get_shape(0); - collided = CollisionSolver3DSW::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis); + collided = GodotCollisionSolver3D::solve_static(shape_A_ptr, xform_A, shape_B_ptr, xform_B, _contact_added_callback, this, &sep_axis); return collided; } -bool BodySoftBodyPair3DSW::pre_solve(real_t p_step) { +bool GodotBodySoftBodyPair3D::pre_solve(real_t p_step) { if (!collided) { return false; } @@ -655,7 +655,7 @@ bool BodySoftBodyPair3DSW::pre_solve(real_t p_step) { real_t bias = (real_t)0.3; - Shape3DSW *shape_A_ptr = body->get_shape(body_shape); + GodotShape3D *shape_A_ptr = body->get_shape(body_shape); if (shape_A_ptr->get_custom_bias()) { bias = shape_A_ptr->get_custom_bias(); @@ -753,7 +753,7 @@ bool BodySoftBodyPair3DSW::pre_solve(real_t p_step) { return do_process; } -void BodySoftBodyPair3DSW::solve(real_t p_step) { +void GodotBodySoftBodyPair3D::solve(real_t p_step) { if (!collided) { return; } @@ -862,8 +862,7 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) { Vector3 temp1 = body_inv_inertia_tensor.xform(c.rA.cross(tv)); - real_t t = -tvl / - (body_inv_mass + node_inv_mass + tv.dot(temp1.cross(c.rA))); + real_t t = -tvl / (body_inv_mass + node_inv_mass + tv.dot(temp1.cross(c.rA))); Vector3 jt = t * tv; @@ -891,8 +890,8 @@ void BodySoftBodyPair3DSW::solve(real_t p_step) { } } -BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B) : - BodyContact3DSW(&body, 1) { +GodotBodySoftBodyPair3D::GodotBodySoftBodyPair3D(GodotBody3D *p_A, int p_shape_A, GodotSoftBody3D *p_B) : + GodotBodyContact3D(&body, 1) { body = p_A; soft_body = p_B; body_shape = p_shape_A; @@ -901,7 +900,7 @@ BodySoftBodyPair3DSW::BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBod soft_body->add_constraint(this); } -BodySoftBodyPair3DSW::~BodySoftBodyPair3DSW() { +GodotBodySoftBodyPair3D::~GodotBodySoftBodyPair3D() { body->remove_constraint(this); soft_body->remove_constraint(this); } diff --git a/servers/physics_3d/body_pair_3d_sw.h b/servers/physics_3d/godot_body_pair_3d.h index 19d6a46880..c0a2424e05 100644 --- a/servers/physics_3d/body_pair_3d_sw.h +++ b/servers/physics_3d/godot_body_pair_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* body_pair_3d_sw.h */ +/* godot_body_pair_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,56 +28,57 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BODY_PAIR_3D_SW_H -#define BODY_PAIR_3D_SW_H +#ifndef GODOT_BODY_PAIR_3D_H +#define GODOT_BODY_PAIR_3D_H + +#include "godot_body_3d.h" +#include "godot_constraint_3d.h" +#include "godot_soft_body_3d.h" -#include "body_3d_sw.h" -#include "constraint_3d_sw.h" #include "core/templates/local_vector.h" -#include "soft_body_3d_sw.h" -class BodyContact3DSW : public Constraint3DSW { +class GodotBodyContact3D : public GodotConstraint3D { protected: struct Contact { Vector3 position; Vector3 normal; - int index_A, index_B; + int index_A = 0, index_B = 0; Vector3 local_A, local_B; - real_t acc_normal_impulse; // accumulated normal impulse (Pn) + real_t acc_normal_impulse = 0.0; // accumulated normal impulse (Pn) Vector3 acc_tangent_impulse; // accumulated tangent impulse (Pt) - real_t acc_bias_impulse; // accumulated normal impulse for position bias (Pnb) - real_t acc_bias_impulse_center_of_mass; // accumulated normal impulse for position bias applied to com - real_t mass_normal; - real_t bias; - real_t bounce; - - real_t depth; - bool active; + real_t acc_bias_impulse = 0.0; // accumulated normal impulse for position bias (Pnb) + real_t acc_bias_impulse_center_of_mass = 0.0; // accumulated normal impulse for position bias applied to com + real_t mass_normal = 0.0; + real_t bias = 0.0; + real_t bounce = 0.0; + + real_t depth = 0.0; + bool active = false; Vector3 rA, rB; // Offset in world orientation with respect to center of mass }; Vector3 sep_axis; bool collided = false; - Space3DSW *space = nullptr; + GodotSpace3D *space = nullptr; - BodyContact3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) : - Constraint3DSW(p_body_ptr, p_body_count) { + GodotBodyContact3D(GodotBody3D **p_body_ptr = nullptr, int p_body_count = 0) : + GodotConstraint3D(p_body_ptr, p_body_count) { } }; -class BodyPair3DSW : public BodyContact3DSW { +class GodotBodyPair3D : public GodotBodyContact3D { enum { MAX_CONTACTS = 4 }; union { struct { - Body3DSW *A; - Body3DSW *B; + GodotBody3D *A; + GodotBody3D *B; }; - Body3DSW *_arr[2] = { nullptr, nullptr }; + GodotBody3D *_arr[2] = { nullptr, nullptr }; }; int shape_A = 0; @@ -98,20 +99,20 @@ class BodyPair3DSW : public BodyContact3DSW { void contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B); void validate_contacts(); - bool _test_ccd(real_t p_step, Body3DSW *p_A, int p_shape_A, const Transform3D &p_xform_A, Body3DSW *p_B, int p_shape_B, const Transform3D &p_xform_B); + bool _test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A, const Transform3D &p_xform_A, GodotBody3D *p_B, int p_shape_B, const Transform3D &p_xform_B); public: virtual bool setup(real_t p_step) override; virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - BodyPair3DSW(Body3DSW *p_A, int p_shape_A, Body3DSW *p_B, int p_shape_B); - ~BodyPair3DSW(); + GodotBodyPair3D(GodotBody3D *p_A, int p_shape_A, GodotBody3D *p_B, int p_shape_B); + ~GodotBodyPair3D(); }; -class BodySoftBodyPair3DSW : public BodyContact3DSW { - Body3DSW *body = nullptr; - SoftBody3DSW *soft_body = nullptr; +class GodotBodySoftBodyPair3D : public GodotBodyContact3D { + GodotBody3D *body = nullptr; + GodotSoftBody3D *soft_body = nullptr; int body_shape = 0; @@ -133,11 +134,11 @@ public: virtual bool pre_solve(real_t p_step) override; virtual void solve(real_t p_step) override; - virtual SoftBody3DSW *get_soft_body_ptr(int p_index) const override { return soft_body; } + virtual GodotSoftBody3D *get_soft_body_ptr(int p_index) const override { return soft_body; } virtual int get_soft_body_count() const override { return 1; } - BodySoftBodyPair3DSW(Body3DSW *p_A, int p_shape_A, SoftBody3DSW *p_B); - ~BodySoftBodyPair3DSW(); + GodotBodySoftBodyPair3D(GodotBody3D *p_A, int p_shape_A, GodotSoftBody3D *p_B); + ~GodotBodySoftBodyPair3D(); }; -#endif // BODY_PAIR_3D_SW_H +#endif // GODOT_BODY_PAIR_3D_H diff --git a/servers/physics_3d/broad_phase_3d_sw.cpp b/servers/physics_3d/godot_broad_phase_3d.cpp index 8aa64034ec..db51dfb2b6 100644 --- a/servers/physics_3d/broad_phase_3d_sw.cpp +++ b/servers/physics_3d/godot_broad_phase_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_3d_sw.cpp */ +/* godot_broad_phase_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,9 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "broad_phase_3d_sw.h" +#include "godot_broad_phase_3d.h" -BroadPhase3DSW::CreateFunction BroadPhase3DSW::create_func = nullptr; +GodotBroadPhase3D::CreateFunction GodotBroadPhase3D::create_func = nullptr; -BroadPhase3DSW::~BroadPhase3DSW() { +GodotBroadPhase3D::~GodotBroadPhase3D() { } diff --git a/servers/physics_3d/broad_phase_3d_sw.h b/servers/physics_3d/godot_broad_phase_3d.h index 98313cb216..65423f293c 100644 --- a/servers/physics_3d/broad_phase_3d_sw.h +++ b/servers/physics_3d/godot_broad_phase_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_3d_sw.h */ +/* godot_broad_phase_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,45 +28,45 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BROAD_PHASE_SW_H -#define BROAD_PHASE_SW_H +#ifndef GODOT_BROAD_PHASE_3D_H +#define GODOT_BROAD_PHASE_3D_H #include "core/math/aabb.h" #include "core/math/math_funcs.h" -class CollisionObject3DSW; +class GodotCollisionObject3D; -class BroadPhase3DSW { +class GodotBroadPhase3D { public: - typedef BroadPhase3DSW *(*CreateFunction)(); + typedef GodotBroadPhase3D *(*CreateFunction)(); static CreateFunction create_func; typedef uint32_t ID; - typedef void *(*PairCallback)(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_userdata); - typedef void (*UnpairCallback)(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_userdata); + typedef void *(*PairCallback)(GodotCollisionObject3D *A, int p_subindex_A, GodotCollisionObject3D *B, int p_subindex_B, void *p_userdata); + typedef void (*UnpairCallback)(GodotCollisionObject3D *A, int p_subindex_A, GodotCollisionObject3D *B, int p_subindex_B, void *p_data, void *p_userdata); // 0 is an invalid ID - virtual ID create(CollisionObject3DSW *p_object_, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false) = 0; + virtual ID create(GodotCollisionObject3D *p_object_, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false) = 0; virtual void move(ID p_id, const AABB &p_aabb) = 0; virtual void set_static(ID p_id, bool p_static) = 0; virtual void remove(ID p_id) = 0; - virtual CollisionObject3DSW *get_object(ID p_id) const = 0; + virtual GodotCollisionObject3D *get_object(ID p_id) const = 0; virtual bool is_static(ID p_id) const = 0; virtual int get_subindex(ID p_id) const = 0; - virtual int cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; - virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; - virtual int cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; + virtual int cull_point(const Vector3 &p_point, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; + virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; + virtual int cull_aabb(const AABB &p_aabb, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices = nullptr) = 0; virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata) = 0; virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) = 0; virtual void update() = 0; - virtual ~BroadPhase3DSW(); + virtual ~GodotBroadPhase3D(); }; -#endif // BROAD_PHASE__SW_H +#endif // GODOT_BROAD_PHASE_3D_H diff --git a/servers/physics_3d/broad_phase_3d_bvh.cpp b/servers/physics_3d/godot_broad_phase_3d_bvh.cpp index f9f64f786d..0f2061a1ea 100644 --- a/servers/physics_3d/broad_phase_3d_bvh.cpp +++ b/servers/physics_3d/godot_broad_phase_3d_bvh.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_3d_bvh.cpp */ +/* godot_broad_phase_3d_bvh.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,55 +28,56 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "broad_phase_3d_bvh.h" -#include "collision_object_3d_sw.h" +#include "godot_broad_phase_3d_bvh.h" -BroadPhase3DBVH::ID BroadPhase3DBVH::create(CollisionObject3DSW *p_object, int p_subindex, const AABB &p_aabb, bool p_static) { +#include "godot_collision_object_3d.h" + +GodotBroadPhase3DBVH::ID GodotBroadPhase3DBVH::create(GodotCollisionObject3D *p_object, int p_subindex, const AABB &p_aabb, bool p_static) { ID oid = bvh.create(p_object, true, p_aabb, p_subindex, !p_static, 1 << p_object->get_type(), p_static ? 0 : 0xFFFFF); // Pair everything, don't care? return oid + 1; } -void BroadPhase3DBVH::move(ID p_id, const AABB &p_aabb) { +void GodotBroadPhase3DBVH::move(ID p_id, const AABB &p_aabb) { bvh.move(p_id - 1, p_aabb); } -void BroadPhase3DBVH::set_static(ID p_id, bool p_static) { - CollisionObject3DSW *it = bvh.get(p_id - 1); +void GodotBroadPhase3DBVH::set_static(ID p_id, bool p_static) { + GodotCollisionObject3D *it = bvh.get(p_id - 1); bvh.set_pairable(p_id - 1, !p_static, 1 << it->get_type(), p_static ? 0 : 0xFFFFF, false); // Pair everything, don't care? } -void BroadPhase3DBVH::remove(ID p_id) { +void GodotBroadPhase3DBVH::remove(ID p_id) { bvh.erase(p_id - 1); } -CollisionObject3DSW *BroadPhase3DBVH::get_object(ID p_id) const { - CollisionObject3DSW *it = bvh.get(p_id - 1); +GodotCollisionObject3D *GodotBroadPhase3DBVH::get_object(ID p_id) const { + GodotCollisionObject3D *it = bvh.get(p_id - 1); ERR_FAIL_COND_V(!it, nullptr); return it; } -bool BroadPhase3DBVH::is_static(ID p_id) const { +bool GodotBroadPhase3DBVH::is_static(ID p_id) const { return !bvh.is_pairable(p_id - 1); } -int BroadPhase3DBVH::get_subindex(ID p_id) const { +int GodotBroadPhase3DBVH::get_subindex(ID p_id) const { return bvh.get_subindex(p_id - 1); } -int BroadPhase3DBVH::cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { +int GodotBroadPhase3DBVH::cull_point(const Vector3 &p_point, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices) { return bvh.cull_point(p_point, p_results, p_max_results, p_result_indices); } -int BroadPhase3DBVH::cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { +int GodotBroadPhase3DBVH::cull_segment(const Vector3 &p_from, const Vector3 &p_to, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices) { return bvh.cull_segment(p_from, p_to, p_results, p_max_results, p_result_indices); } -int BroadPhase3DBVH::cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices) { +int GodotBroadPhase3DBVH::cull_aabb(const AABB &p_aabb, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices) { return bvh.cull_aabb(p_aabb, p_results, p_max_results, p_result_indices); } -void *BroadPhase3DBVH::_pair_callback(void *self, uint32_t p_A, CollisionObject3DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject3DSW *p_object_B, int subindex_B) { - BroadPhase3DBVH *bpo = (BroadPhase3DBVH *)(self); +void *GodotBroadPhase3DBVH::_pair_callback(void *self, uint32_t p_A, GodotCollisionObject3D *p_object_A, int subindex_A, uint32_t p_B, GodotCollisionObject3D *p_object_B, int subindex_B) { + GodotBroadPhase3DBVH *bpo = (GodotBroadPhase3DBVH *)(self); if (!bpo->pair_callback) { return nullptr; } @@ -84,8 +85,8 @@ void *BroadPhase3DBVH::_pair_callback(void *self, uint32_t p_A, CollisionObject3 return bpo->pair_callback(p_object_A, subindex_A, p_object_B, subindex_B, bpo->pair_userdata); } -void BroadPhase3DBVH::_unpair_callback(void *self, uint32_t p_A, CollisionObject3DSW *p_object_A, int subindex_A, uint32_t p_B, CollisionObject3DSW *p_object_B, int subindex_B, void *pairdata) { - BroadPhase3DBVH *bpo = (BroadPhase3DBVH *)(self); +void GodotBroadPhase3DBVH::_unpair_callback(void *self, uint32_t p_A, GodotCollisionObject3D *p_object_A, int subindex_A, uint32_t p_B, GodotCollisionObject3D *p_object_B, int subindex_B, void *pairdata) { + GodotBroadPhase3DBVH *bpo = (GodotBroadPhase3DBVH *)(self); if (!bpo->unpair_callback) { return; } @@ -93,28 +94,25 @@ void BroadPhase3DBVH::_unpair_callback(void *self, uint32_t p_A, CollisionObject bpo->unpair_callback(p_object_A, subindex_A, p_object_B, subindex_B, pairdata, bpo->unpair_userdata); } -void BroadPhase3DBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { +void GodotBroadPhase3DBVH::set_pair_callback(PairCallback p_pair_callback, void *p_userdata) { pair_callback = p_pair_callback; pair_userdata = p_userdata; } -void BroadPhase3DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { +void GodotBroadPhase3DBVH::set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata) { unpair_callback = p_unpair_callback; unpair_userdata = p_userdata; } -void BroadPhase3DBVH::update() { +void GodotBroadPhase3DBVH::update() { bvh.update(); } -BroadPhase3DSW *BroadPhase3DBVH::_create() { - return memnew(BroadPhase3DBVH); +GodotBroadPhase3D *GodotBroadPhase3DBVH::_create() { + return memnew(GodotBroadPhase3DBVH); } -BroadPhase3DBVH::BroadPhase3DBVH() { +GodotBroadPhase3DBVH::GodotBroadPhase3DBVH() { bvh.set_pair_callback(_pair_callback, this); bvh.set_unpair_callback(_unpair_callback, this); - pair_callback = nullptr; - pair_userdata = nullptr; - unpair_userdata = nullptr; } diff --git a/servers/physics_3d/broad_phase_3d_bvh.h b/servers/physics_3d/godot_broad_phase_3d_bvh.h index 30b8b7f2aa..61127e52c1 100644 --- a/servers/physics_3d/broad_phase_3d_bvh.h +++ b/servers/physics_3d/godot_broad_phase_3d_bvh.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* broad_phase_3d_bvh.h */ +/* godot_broad_phase_3d_bvh.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,45 +28,46 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef BROAD_PHASE_3D_BVH_H -#define BROAD_PHASE_3D_BVH_H +#ifndef GODOT_BROAD_PHASE_3D_BVH_H +#define GODOT_BROAD_PHASE_3D_BVH_H + +#include "godot_broad_phase_3d.h" -#include "broad_phase_3d_sw.h" #include "core/math/bvh.h" -class BroadPhase3DBVH : public BroadPhase3DSW { - BVH_Manager<CollisionObject3DSW, true, 128> bvh; +class GodotBroadPhase3DBVH : public GodotBroadPhase3D { + BVH_Manager<GodotCollisionObject3D, true, 128> bvh; - static void *_pair_callback(void *, uint32_t, CollisionObject3DSW *, int, uint32_t, CollisionObject3DSW *, int); - static void _unpair_callback(void *, uint32_t, CollisionObject3DSW *, int, uint32_t, CollisionObject3DSW *, int, void *); + static void *_pair_callback(void *, uint32_t, GodotCollisionObject3D *, int, uint32_t, GodotCollisionObject3D *, int); + static void _unpair_callback(void *, uint32_t, GodotCollisionObject3D *, int, uint32_t, GodotCollisionObject3D *, int, void *); - PairCallback pair_callback; - void *pair_userdata; - UnpairCallback unpair_callback; - void *unpair_userdata; + PairCallback pair_callback = nullptr; + void *pair_userdata = nullptr; + UnpairCallback unpair_callback = nullptr; + void *unpair_userdata = nullptr; public: // 0 is an invalid ID - virtual ID create(CollisionObject3DSW *p_object, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false); + virtual ID create(GodotCollisionObject3D *p_object, int p_subindex = 0, const AABB &p_aabb = AABB(), bool p_static = false); virtual void move(ID p_id, const AABB &p_aabb); virtual void set_static(ID p_id, bool p_static); virtual void remove(ID p_id); - virtual CollisionObject3DSW *get_object(ID p_id) const; + virtual GodotCollisionObject3D *get_object(ID p_id) const; virtual bool is_static(ID p_id) const; virtual int get_subindex(ID p_id) const; - virtual int cull_point(const Vector3 &p_point, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr); - virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr); - virtual int cull_aabb(const AABB &p_aabb, CollisionObject3DSW **p_results, int p_max_results, int *p_result_indices = nullptr); + virtual int cull_point(const Vector3 &p_point, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices = nullptr); + virtual int cull_segment(const Vector3 &p_from, const Vector3 &p_to, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices = nullptr); + virtual int cull_aabb(const AABB &p_aabb, GodotCollisionObject3D **p_results, int p_max_results, int *p_result_indices = nullptr); virtual void set_pair_callback(PairCallback p_pair_callback, void *p_userdata); virtual void set_unpair_callback(UnpairCallback p_unpair_callback, void *p_userdata); virtual void update(); - static BroadPhase3DSW *_create(); - BroadPhase3DBVH(); + static GodotBroadPhase3D *_create(); + GodotBroadPhase3DBVH(); }; -#endif // BROAD_PHASE_3D_BVH_H +#endif // GODOT_BROAD_PHASE_3D_BVH_H diff --git a/servers/physics_3d/collision_object_3d_sw.cpp b/servers/physics_3d/godot_collision_object_3d.cpp index 24c7d7b85c..421291011b 100644 --- a/servers/physics_3d/collision_object_3d_sw.cpp +++ b/servers/physics_3d/godot_collision_object_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_object_3d_sw.cpp */ +/* godot_collision_object_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,12 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "collision_object_3d_sw.h" -#include "servers/physics_3d/physics_server_3d_sw.h" -#include "space_3d_sw.h" +#include "godot_collision_object_3d.h" -void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform3D &p_transform, bool p_disabled) { +#include "godot_physics_server_3d.h" +#include "godot_space_3d.h" + +void GodotCollisionObject3D::add_shape(GodotShape3D *p_shape, const Transform3D &p_transform, bool p_disabled) { Shape s; s.shape = p_shape; s.xform = p_transform; @@ -43,35 +44,35 @@ void CollisionObject3DSW::add_shape(Shape3DSW *p_shape, const Transform3D &p_tra p_shape->add_owner(this); if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer3D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } -void CollisionObject3DSW::set_shape(int p_index, Shape3DSW *p_shape) { +void GodotCollisionObject3D::set_shape(int p_index, GodotShape3D *p_shape) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes[p_index].shape->remove_owner(this); shapes.write[p_index].shape = p_shape; p_shape->add_owner(this); if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer3D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } -void CollisionObject3DSW::set_shape_transform(int p_index, const Transform3D &p_transform) { +void GodotCollisionObject3D::set_shape_transform(int p_index, const Transform3D &p_transform) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes.write[p_index].xform = p_transform; shapes.write[p_index].xform_inv = p_transform.affine_inverse(); if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer3D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } -void CollisionObject3DSW::set_shape_disabled(int p_idx, bool p_disabled) { +void GodotCollisionObject3D::set_shape_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, shapes.size()); - CollisionObject3DSW::Shape &shape = shapes.write[p_idx]; + GodotCollisionObject3D::Shape &shape = shapes.write[p_idx]; if (shape.disabled == p_disabled) { return; } @@ -86,16 +87,16 @@ void CollisionObject3DSW::set_shape_disabled(int p_idx, bool p_disabled) { space->get_broadphase()->remove(shape.bpid); shape.bpid = 0; if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer3D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } else if (!p_disabled && shape.bpid == 0) { if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer3D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } } -void CollisionObject3DSW::remove_shape(Shape3DSW *p_shape) { +void GodotCollisionObject3D::remove_shape(GodotShape3D *p_shape) { //remove a shape, all the times it appears for (int i = 0; i < shapes.size(); i++) { if (shapes[i].shape == p_shape) { @@ -105,7 +106,7 @@ void CollisionObject3DSW::remove_shape(Shape3DSW *p_shape) { } } -void CollisionObject3DSW::remove_shape(int p_index) { +void GodotCollisionObject3D::remove_shape(int p_index) { //remove anything from shape to be erased to end, so subindices don't change ERR_FAIL_INDEX(p_index, shapes.size()); for (int i = p_index; i < shapes.size(); i++) { @@ -117,14 +118,14 @@ void CollisionObject3DSW::remove_shape(int p_index) { shapes.write[i].bpid = 0; } shapes[p_index].shape->remove_owner(this); - shapes.remove(p_index); + shapes.remove_at(p_index); if (!pending_shape_update_list.in_list()) { - PhysicsServer3DSW::singletonsw->pending_shape_update_list.add(&pending_shape_update_list); + GodotPhysicsServer3D::godot_singleton->pending_shape_update_list.add(&pending_shape_update_list); } } -void CollisionObject3DSW::_set_static(bool p_static) { +void GodotCollisionObject3D::_set_static(bool p_static) { if (_static == p_static) { return; } @@ -141,7 +142,7 @@ void CollisionObject3DSW::_set_static(bool p_static) { } } -void CollisionObject3DSW::_unregister_shapes() { +void GodotCollisionObject3D::_unregister_shapes() { for (int i = 0; i < shapes.size(); i++) { Shape &s = shapes.write[i]; if (s.bpid > 0) { @@ -151,7 +152,7 @@ void CollisionObject3DSW::_unregister_shapes() { } } -void CollisionObject3DSW::_update_shapes() { +void GodotCollisionObject3D::_update_shapes() { if (!space) { return; } @@ -170,7 +171,7 @@ void CollisionObject3DSW::_update_shapes() { s.aabb_cache = shape_aabb; Vector3 scale = xform.get_basis().get_scale(); - s.area_cache = s.shape->get_area() * scale.x * scale.y * scale.z; + s.area_cache = s.shape->get_volume() * scale.x * scale.y * scale.z; if (s.bpid == 0) { s.bpid = space->get_broadphase()->create(this, i, shape_aabb, _static); @@ -181,7 +182,7 @@ void CollisionObject3DSW::_update_shapes() { } } -void CollisionObject3DSW::_update_shapes_with_motion(const Vector3 &p_motion) { +void GodotCollisionObject3D::_update_shapes_with_motion(const Vector3 &p_motion) { if (!space) { return; } @@ -208,7 +209,7 @@ void CollisionObject3DSW::_update_shapes_with_motion(const Vector3 &p_motion) { } } -void CollisionObject3DSW::_set_space(Space3DSW *p_space) { +void GodotCollisionObject3D::_set_space(GodotSpace3D *p_space) { if (space) { space->remove_object(this); @@ -229,18 +230,12 @@ void CollisionObject3DSW::_set_space(Space3DSW *p_space) { } } -void CollisionObject3DSW::_shape_changed() { +void GodotCollisionObject3D::_shape_changed() { _update_shapes(); _shapes_changed(); } -CollisionObject3DSW::CollisionObject3DSW(Type p_type) : +GodotCollisionObject3D::GodotCollisionObject3D(Type p_type) : pending_shape_update_list(this) { - _static = true; type = p_type; - space = nullptr; - - collision_layer = 1; - collision_mask = 1; - ray_pickable = true; } diff --git a/servers/physics_3d/collision_object_3d_sw.h b/servers/physics_3d/godot_collision_object_3d.h index 6ffab54645..43558034e0 100644 --- a/servers/physics_3d/collision_object_3d_sw.h +++ b/servers/physics_3d/godot_collision_object_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_object_3d_sw.h */ +/* godot_collision_object_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef COLLISION_OBJECT_SW_H -#define COLLISION_OBJECT_SW_H +#ifndef GODOT_COLLISION_OBJECT_3D_H +#define GODOT_COLLISION_OBJECT_3D_H + +#include "godot_broad_phase_3d.h" +#include "godot_shape_3d.h" -#include "broad_phase_3d_sw.h" #include "core/templates/self_list.h" #include "servers/physics_server_3d.h" -#include "shape_3d_sw.h" #ifdef DEBUG_ENABLED #define MAX_OBJECT_DISTANCE 3.1622776601683791e+18 @@ -42,9 +43,9 @@ #define MAX_OBJECT_DISTANCE_X2 (MAX_OBJECT_DISTANCE * MAX_OBJECT_DISTANCE) #endif -class Space3DSW; +class GodotSpace3D; -class CollisionObject3DSW : public ShapeOwner3DSW { +class GodotCollisionObject3D : public GodotShapeOwner3D { public: enum Type { TYPE_AREA, @@ -56,28 +57,26 @@ private: Type type; RID self; ObjectID instance_id; - uint32_t collision_layer; - uint32_t collision_mask; + uint32_t collision_layer = 1; + uint32_t collision_mask = 1; struct Shape { Transform3D xform; Transform3D xform_inv; - BroadPhase3DSW::ID bpid; + GodotBroadPhase3D::ID bpid; AABB aabb_cache; //for rayqueries - real_t area_cache; - Shape3DSW *shape; - bool disabled; - - Shape() { disabled = false; } + real_t area_cache = 0.0; + GodotShape3D *shape = nullptr; + bool disabled = false; }; Vector<Shape> shapes; - Space3DSW *space; + GodotSpace3D *space = nullptr; Transform3D transform; Transform3D inv_transform; - bool _static; + bool _static = true; - SelfList<CollisionObject3DSW> pending_shape_update_list; + SelfList<GodotCollisionObject3D> pending_shape_update_list; void _update_shapes(); @@ -100,11 +99,11 @@ protected: void _set_static(bool p_static); virtual void _shapes_changed() = 0; - void _set_space(Space3DSW *p_space); + void _set_space(GodotSpace3D *p_space); - bool ray_pickable; + bool ray_pickable = true; - CollisionObject3DSW(Type p_type); + GodotCollisionObject3D(Type p_type); public: _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; } @@ -116,11 +115,11 @@ public: void _shape_changed(); _FORCE_INLINE_ Type get_type() const { return type; } - void add_shape(Shape3DSW *p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false); - void set_shape(int p_index, Shape3DSW *p_shape); + void add_shape(GodotShape3D *p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false); + void set_shape(int p_index, GodotShape3D *p_shape); void set_shape_transform(int p_index, const Transform3D &p_transform); _FORCE_INLINE_ int get_shape_count() const { return shapes.size(); } - _FORCE_INLINE_ Shape3DSW *get_shape(int p_index) const { + _FORCE_INLINE_ GodotShape3D *get_shape(int p_index) const { CRASH_BAD_INDEX(p_index, shapes.size()); return shapes[p_index].shape; } @@ -143,7 +142,7 @@ public: _FORCE_INLINE_ const Transform3D &get_transform() const { return transform; } _FORCE_INLINE_ const Transform3D &get_inv_transform() const { return inv_transform; } - _FORCE_INLINE_ Space3DSW *get_space() const { return space; } + _FORCE_INLINE_ GodotSpace3D *get_space() const { return space; } _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; } _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; } @@ -166,22 +165,22 @@ public: } _FORCE_INLINE_ uint32_t get_collision_mask() const { return collision_mask; } - _FORCE_INLINE_ bool collides_with(CollisionObject3DSW *p_other) const { + _FORCE_INLINE_ bool collides_with(GodotCollisionObject3D *p_other) const { return p_other->collision_layer & collision_mask; } - _FORCE_INLINE_ bool interacts_with(CollisionObject3DSW *p_other) const { + _FORCE_INLINE_ bool interacts_with(GodotCollisionObject3D *p_other) const { return collision_layer & p_other->collision_mask || p_other->collision_layer & collision_mask; } - void remove_shape(Shape3DSW *p_shape); + void remove_shape(GodotShape3D *p_shape); void remove_shape(int p_index); - virtual void set_space(Space3DSW *p_space) = 0; + virtual void set_space(GodotSpace3D *p_space) = 0; _FORCE_INLINE_ bool is_static() const { return _static; } - virtual ~CollisionObject3DSW() {} + virtual ~GodotCollisionObject3D() {} }; -#endif // COLLISION_OBJECT_SW_H +#endif // GODOT_COLLISION_OBJECT_3D_H diff --git a/servers/physics_3d/collision_solver_3d_sw.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp index 4a4a8164d3..540b16c6e3 100644 --- a/servers/physics_3d/collision_solver_3d_sw.cpp +++ b/servers/physics_3d/godot_collision_solver_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_solver_3d_sw.cpp */ +/* godot_collision_solver_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,29 +28,29 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "collision_solver_3d_sw.h" -#include "collision_solver_3d_sat.h" -#include "soft_body_3d_sw.h" +#include "godot_collision_solver_3d.h" +#include "godot_collision_solver_3d_sat.h" +#include "godot_soft_body_3d.h" #include "gjk_epa.h" #define collision_solver sat_calculate_penetration //#define collision_solver gjk_epa_calculate_penetration -bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { - const PlaneShape3DSW *plane = static_cast<const PlaneShape3DSW *>(p_shape_A); - if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) { +bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { + const GodotWorldBoundaryShape3D *world_boundary = static_cast<const GodotWorldBoundaryShape3D *>(p_shape_A); + if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { return false; } - Plane p = p_transform_A.xform(plane->get_plane()); + Plane p = p_transform_A.xform(world_boundary->get_plane()); static const int max_supports = 16; Vector3 supports[max_supports]; int support_count; - Shape3DSW::FeatureType support_type; + GodotShape3D::FeatureType support_type; p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type); - if (support_type == Shape3DSW::FEATURE_CIRCLE) { + if (support_type == GodotShape3D::FEATURE_CIRCLE) { ERR_FAIL_COND_V(support_count != 3, false); Vector3 circle_pos = supports[0]; @@ -89,8 +89,8 @@ bool CollisionSolver3DSW::solve_static_plane(const Shape3DSW *p_shape_A, const T return found; } -bool CollisionSolver3DSW::solve_separation_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin) { - const SeparationRayShape3DSW *ray = static_cast<const SeparationRayShape3DSW *>(p_shape_A); +bool GodotCollisionSolver3D::solve_separation_ray(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin) { + const GodotSeparationRayShape3D *ray = static_cast<const GodotSeparationRayShape3D *>(p_shape_A); Vector3 from = p_transform_A.origin; Vector3 to = from + p_transform_A.basis.get_axis(2) * (ray->get_length() + p_margin); @@ -102,7 +102,7 @@ bool CollisionSolver3DSW::solve_separation_ray(const Shape3DSW *p_shape_A, const to = ai.xform(to); Vector3 p, n; - if (!p_shape_B->intersect_segment(from, to, p, n)) { + if (!p_shape_B->intersect_segment(from, to, p, n, true)) { return false; } @@ -134,13 +134,13 @@ bool CollisionSolver3DSW::solve_separation_ray(const Shape3DSW *p_shape_A, const struct _SoftBodyContactCollisionInfo { int node_index = 0; - CollisionSolver3DSW::CallbackResult result_callback = nullptr; + GodotCollisionSolver3D::CallbackResult result_callback = nullptr; void *userdata = nullptr; bool swap_result = false; int contact_count = 0; }; -void CollisionSolver3DSW::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { +void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { _SoftBodyContactCollisionInfo &cinfo = *(_SoftBodyContactCollisionInfo *)(p_userdata); ++cinfo.contact_count; @@ -157,9 +157,9 @@ void CollisionSolver3DSW::soft_body_contact_callback(const Vector3 &p_point_A, i } struct _SoftBodyQueryInfo { - SoftBody3DSW *soft_body = nullptr; - const Shape3DSW *shape_A = nullptr; - const Shape3DSW *shape_B = nullptr; + GodotSoftBody3D *soft_body = nullptr; + const GodotShape3D *shape_A = nullptr; + const GodotShape3D *shape_B = nullptr; Transform3D transform_A; Transform3D node_transform; _SoftBodyContactCollisionInfo contact_info; @@ -169,7 +169,7 @@ struct _SoftBodyQueryInfo { #endif }; -bool CollisionSolver3DSW::soft_body_query_callback(uint32_t p_node_index, void *p_userdata) { +bool GodotCollisionSolver3D::soft_body_query_callback(uint32_t p_node_index, void *p_userdata) { _SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata); Vector3 node_position = query_cinfo.soft_body->get_node_position(p_node_index); @@ -188,7 +188,7 @@ bool CollisionSolver3DSW::soft_body_query_callback(uint32_t p_node_index, void * return (collided && !query_cinfo.contact_info.result_callback); } -bool CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex) { +bool GodotCollisionSolver3D::soft_body_concave_callback(void *p_userdata, GodotShape3D *p_convex) { _SoftBodyQueryInfo &query_cinfo = *(_SoftBodyQueryInfo *)(p_userdata); query_cinfo.shape_A = p_convex; @@ -220,15 +220,15 @@ bool CollisionSolver3DSW::soft_body_concave_callback(void *p_userdata, Shape3DSW return (collided && !query_cinfo.contact_info.result_callback); } -bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { - const SoftBodyShape3DSW *soft_body_shape_B = static_cast<const SoftBodyShape3DSW *>(p_shape_B); +bool GodotCollisionSolver3D::solve_soft_body(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result) { + const GodotSoftBodyShape3D *soft_body_shape_B = static_cast<const GodotSoftBodyShape3D *>(p_shape_B); - SoftBody3DSW *soft_body = soft_body_shape_B->get_soft_body(); + GodotSoftBody3D *soft_body = soft_body_shape_B->get_soft_body(); const Transform3D &world_to_local = soft_body->get_inv_transform(); const real_t collision_margin = soft_body->get_collision_margin(); - SphereShape3DSW sphere_shape; + GodotSphereShape3D sphere_shape; sphere_shape.set_data(collision_margin); _SoftBodyQueryInfo query_cinfo; @@ -243,7 +243,7 @@ bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Tran if (p_shape_A->is_concave()) { // In case of concave shape, query convex shapes first. - const ConcaveShape3DSW *concave_shape_A = static_cast<const ConcaveShape3DSW *>(p_shape_A); + const GodotConcaveShape3D *concave_shape_A = static_cast<const GodotConcaveShape3D *>(p_shape_A); AABB soft_body_aabb = soft_body->get_bounds(); soft_body_aabb.grow_by(collision_margin); @@ -264,7 +264,7 @@ bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Tran local_aabb.size[i] = smax - smin; } - concave_shape_A->cull(local_aabb, soft_body_concave_callback, &query_cinfo); + concave_shape_A->cull(local_aabb, soft_body_concave_callback, &query_cinfo, true); } else { AABB shape_aabb = p_transform_A.xform(p_shape_A->get_aabb()); shape_aabb.grow_by(collision_margin); @@ -277,9 +277,9 @@ bool CollisionSolver3DSW::solve_soft_body(const Shape3DSW *p_shape_A, const Tran struct _ConcaveCollisionInfo { const Transform3D *transform_A; - const Shape3DSW *shape_A; + const GodotShape3D *shape_A; const Transform3D *transform_B; - CollisionSolver3DSW::CallbackResult result_callback; + GodotCollisionSolver3D::CallbackResult result_callback; void *userdata; bool swap_result; bool collided; @@ -291,7 +291,7 @@ struct _ConcaveCollisionInfo { Vector3 close_A, close_B; }; -bool CollisionSolver3DSW::concave_callback(void *p_userdata, Shape3DSW *p_convex) { +bool GodotCollisionSolver3D::concave_callback(void *p_userdata, GodotShape3D *p_convex) { _ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata); cinfo.aabb_tests++; @@ -307,8 +307,8 @@ bool CollisionSolver3DSW::concave_callback(void *p_userdata, Shape3DSW *p_convex return !cinfo.result_callback; } -bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A, real_t p_margin_B) { - const ConcaveShape3DSW *concave_B = static_cast<const ConcaveShape3DSW *>(p_shape_B); +bool GodotCollisionSolver3D::solve_concave(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A, real_t p_margin_B) { + const GodotConcaveShape3D *concave_B = static_cast<const GodotConcaveShape3D *>(p_shape_B); _ConcaveCollisionInfo cinfo; cinfo.transform_A = &p_transform_A; @@ -346,12 +346,12 @@ bool CollisionSolver3DSW::solve_concave(const Shape3DSW *p_shape_A, const Transf local_aabb.size[i] = smax - smin; } - concave_B->cull(local_aabb, concave_callback, &cinfo); + concave_B->cull(local_aabb, concave_callback, &cinfo, false); return cinfo.collided; } -bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) { +bool GodotCollisionSolver3D::solve_static(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis, real_t p_margin_A, real_t p_margin_B) { PhysicsServer3D::ShapeType type_A = p_shape_A->get_type(); PhysicsServer3D::ShapeType type_B = p_shape_B->get_type(); bool concave_A = p_shape_A->is_concave(); @@ -365,8 +365,8 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo swap = true; } - if (type_A == PhysicsServer3D::SHAPE_PLANE) { - if (type_B == PhysicsServer3D::SHAPE_PLANE) { + if (type_A == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { + if (type_B == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { return false; } if (type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY) { @@ -377,9 +377,9 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo } if (swap) { - return solve_static_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); + return solve_static_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, p_result_callback, p_userdata, true); } else { - return solve_static_plane(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); + return solve_static_world_boundary(p_shape_A, p_transform_A, p_shape_B, p_transform_B, p_result_callback, p_userdata, false); } } else if (type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY) { @@ -421,7 +421,7 @@ bool CollisionSolver3DSW::solve_static(const Shape3DSW *p_shape_A, const Transfo } } -bool CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW *p_convex) { +bool GodotCollisionSolver3D::concave_distance_callback(void *p_userdata, GodotShape3D *p_convex) { _ConcaveCollisionInfo &cinfo = *(_ConcaveCollisionInfo *)(p_userdata); cinfo.aabb_tests++; @@ -443,21 +443,21 @@ bool CollisionSolver3DSW::concave_distance_callback(void *p_userdata, Shape3DSW return false; } -bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) { - const PlaneShape3DSW *plane = static_cast<const PlaneShape3DSW *>(p_shape_A); - if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) { +bool GodotCollisionSolver3D::solve_distance_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B) { + const GodotWorldBoundaryShape3D *world_boundary = static_cast<const GodotWorldBoundaryShape3D *>(p_shape_A); + if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { return false; } - Plane p = p_transform_A.xform(plane->get_plane()); + Plane p = p_transform_A.xform(world_boundary->get_plane()); static const int max_supports = 16; Vector3 supports[max_supports]; int support_count; - Shape3DSW::FeatureType support_type; + GodotShape3D::FeatureType support_type; p_shape_B->get_supports(p_transform_B.basis.xform_inv(-p.normal).normalized(), max_supports, supports, support_count, support_type); - if (support_type == Shape3DSW::FEATURE_CIRCLE) { + if (support_type == GodotShape3D::FEATURE_CIRCLE) { ERR_FAIL_COND_V(support_count != 3, false); Vector3 circle_pos = supports[0]; @@ -495,14 +495,14 @@ bool CollisionSolver3DSW::solve_distance_plane(const Shape3DSW *p_shape_A, const return collided; } -bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis) { +bool GodotCollisionSolver3D::solve_distance(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis) { if (p_shape_A->is_concave()) { return false; } - if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_PLANE) { + if (p_shape_B->get_type() == PhysicsServer3D::SHAPE_WORLD_BOUNDARY) { Vector3 a, b; - bool col = solve_distance_plane(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b); + bool col = solve_distance_world_boundary(p_shape_B, p_transform_B, p_shape_A, p_transform_A, a, b); r_point_A = b; r_point_B = a; return !col; @@ -512,7 +512,7 @@ bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Trans return false; } - const ConcaveShape3DSW *concave_B = static_cast<const ConcaveShape3DSW *>(p_shape_B); + const GodotConcaveShape3D *concave_B = static_cast<const GodotConcaveShape3D *>(p_shape_B); _ConcaveCollisionInfo cinfo; cinfo.transform_A = &p_transform_A; @@ -547,7 +547,7 @@ bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Trans real_t smin, smax; if (use_cc_hint) { - cc_hint_aabb.project_range_in_plane(Plane(axis, 0), smin, smax); + cc_hint_aabb.project_range_in_plane(Plane(axis), smin, smax); } else { p_shape_A->project_range(axis, rel_transform, smin, smax); } @@ -559,7 +559,7 @@ bool CollisionSolver3DSW::solve_distance(const Shape3DSW *p_shape_A, const Trans local_aabb.size[i] = smax - smin; } - concave_B->cull(local_aabb, concave_distance_callback, &cinfo); + concave_B->cull(local_aabb, concave_distance_callback, &cinfo, false); if (!cinfo.collided) { r_point_A = cinfo.close_A; r_point_B = cinfo.close_B; diff --git a/servers/physics_3d/collision_solver_3d_sw.h b/servers/physics_3d/godot_collision_solver_3d.h index c13614ab3e..133635ca7e 100644 --- a/servers/physics_3d/collision_solver_3d_sw.h +++ b/servers/physics_3d/godot_collision_solver_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_solver_3d_sw.h */ +/* godot_collision_solver_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,30 +28,30 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef COLLISION_SOLVER_SW_H -#define COLLISION_SOLVER_SW_H +#ifndef GODOT_COLLISION_SOLVER_3D_H +#define GODOT_COLLISION_SOLVER_3D_H -#include "shape_3d_sw.h" +#include "godot_shape_3d.h" -class CollisionSolver3DSW { +class GodotCollisionSolver3D { public: typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); private: static bool soft_body_query_callback(uint32_t p_node_index, void *p_userdata); static void soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); - static bool soft_body_concave_callback(void *p_userdata, Shape3DSW *p_convex); - static bool concave_callback(void *p_userdata, Shape3DSW *p_convex); - static bool solve_static_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); - static bool solve_separation_ray(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0); - static bool solve_soft_body(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); - static bool solve_concave(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0); - static bool concave_distance_callback(void *p_userdata, Shape3DSW *p_convex); - static bool solve_distance_plane(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B); + static bool soft_body_concave_callback(void *p_userdata, GodotShape3D *p_convex); + static bool concave_callback(void *p_userdata, GodotShape3D *p_convex); + static bool solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool solve_separation_ray(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0); + static bool solve_soft_body(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result); + static bool solve_concave(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin_A = 0, real_t p_margin_B = 0); + static bool concave_distance_callback(void *p_userdata, GodotShape3D *p_convex); + static bool solve_distance_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B); public: - static bool solve_static(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); - static bool solve_distance(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis = nullptr); + static bool solve_static(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, Vector3 *r_sep_axis = nullptr, real_t p_margin_A = 0, real_t p_margin_B = 0); + static bool solve_distance(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, Vector3 &r_point_A, Vector3 &r_point_B, const AABB &p_concave_hint, Vector3 *r_sep_axis = nullptr); }; -#endif // COLLISION_SOLVER__SW_H +#endif // GODOT_COLLISION_SOLVER_3D_H diff --git a/servers/physics_3d/collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp index de81348b4e..4faa07b6c9 100644 --- a/servers/physics_3d/collision_solver_3d_sat.cpp +++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_solver_3d_sat.cpp */ +/* godot_collision_solver_3d_sat.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,16 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "collision_solver_3d_sat.h" -#include "core/math/geometry_3d.h" +#include "godot_collision_solver_3d_sat.h" #include "gjk_epa.h" +#include "core/math/geometry_3d.h" + #define fallback_collision_solver gjk_epa_calculate_penetration +#define _BACKFACE_NORMAL_THRESHOLD -0.0002 + // Cylinder SAT analytic methods and face-circle contact points for cylinder-trimesh and cylinder-box collision are based on ODE colliders. /* @@ -65,12 +68,12 @@ *************************************************************************/ struct _CollectorCallback { - CollisionSolver3DSW::CallbackResult callback; - void *userdata; - bool swap; - bool collided; + GodotCollisionSolver3D::CallbackResult callback; + void *userdata = nullptr; + bool swap = false; + bool collided = false; Vector3 normal; - Vector3 *prev_axis; + Vector3 *prev_axis = nullptr; _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) { if (swap) { @@ -183,7 +186,7 @@ static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_poin real_t circle_B_radius = circle_B_line_1.length(); Vector3 circle_B_normal = circle_B_line_1.cross(circle_B_line_2).normalized(); - Plane circle_plane(circle_B_pos, circle_B_normal); + Plane circle_plane(circle_B_normal, circle_B_pos); static const int max_clip = 2; Vector3 contact_points[max_clip]; @@ -299,7 +302,7 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_ Vector3 clip_normal = (edge0_B - edge1_B).cross(plane_B.normal).normalized(); // make a clip plane - Plane clip(edge0_B, clip_normal); + Plane clip(clip_normal, edge0_B); // avoid double clip if A is edge int dst_idx = 0; bool edge = clipbuf_len == 2; @@ -385,7 +388,7 @@ static void _generate_contacts_face_circle(const Vector3 *p_points_A, int p_poin // Clip face with circle plane. Vector3 circle_B_normal = circle_B_line_1.cross(circle_B_line_2).normalized(); - Plane circle_plane(circle_B_pos, circle_B_normal); + Plane circle_plane(circle_B_normal, circle_B_pos); static const int max_clip = 32; Vector3 contact_points[max_clip]; @@ -522,7 +525,7 @@ static void _generate_contacts_circle_circle(const Vector3 *p_points_A, int p_po } } - Plane circle_B_plane(circle_B_pos, circle_B_normal); + Plane circle_B_plane(circle_B_normal, circle_B_pos); // Generate contact points. for (int i = 0; i < num_points; i++) { @@ -539,7 +542,7 @@ static void _generate_contacts_circle_circle(const Vector3 *p_points_A, int p_po } } -static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_point_count_A, Shape3DSW::FeatureType p_feature_type_A, const Vector3 *p_points_B, int p_point_count_B, Shape3DSW::FeatureType p_feature_type_B, _CollectorCallback *p_callback) { +static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_point_count_A, GodotShape3D::FeatureType p_feature_type_A, const Vector3 *p_points_B, int p_point_count_B, GodotShape3D::FeatureType p_feature_type_B, _CollectorCallback *p_callback) { #ifdef DEBUG_ENABLED ERR_FAIL_COND(p_point_count_A < 1); ERR_FAIL_COND(p_point_count_B < 1); @@ -606,18 +609,19 @@ static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_po template <class ShapeA, class ShapeB, bool withMargin = false> class SeparatorAxisTest { - const ShapeA *shape_A; - const ShapeB *shape_B; - const Transform3D *transform_A; - const Transform3D *transform_B; - real_t best_depth; - Vector3 best_axis; - _CollectorCallback *callback; - real_t margin_A; - real_t margin_B; + const ShapeA *shape_A = nullptr; + const ShapeB *shape_B = nullptr; + const Transform3D *transform_A = nullptr; + const Transform3D *transform_B = nullptr; + real_t best_depth = 1e15; + _CollectorCallback *callback = nullptr; + real_t margin_A = 0.0; + real_t margin_B = 0.0; Vector3 separator_axis; public: + Vector3 best_axis; + _FORCE_INLINE_ bool test_previous_axis() { if (callback && callback->prev_axis && *callback->prev_axis != Vector3()) { return test_axis(*callback->prev_axis); @@ -626,7 +630,7 @@ public: } } - _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis, bool p_directional = false) { + _FORCE_INLINE_ bool test_axis(const Vector3 &p_axis) { Vector3 axis = p_axis; if (axis.is_equal_approx(Vector3())) { @@ -660,12 +664,7 @@ public: //use the smallest depth if (min_B < 0.0) { // could be +0.0, we don't want it to become -0.0 - if (p_directional) { - min_B = max_B; - axis = -axis; - } else { - min_B = -min_B; - } + min_B = -min_B; } if (max_B < min_B) { @@ -713,7 +712,7 @@ public: Vector3 supports_A[max_supports]; int support_count_A; - Shape3DSW::FeatureType support_type_A; + GodotShape3D::FeatureType support_type_A; shape_A->get_supports(transform_A->basis.xform_inv(-best_axis).normalized(), max_supports, supports_A, support_count_A, support_type_A); for (int i = 0; i < support_count_A; i++) { supports_A[i] = transform_A->xform(supports_A[i]); @@ -727,7 +726,7 @@ public: Vector3 supports_B[max_supports]; int support_count_B; - Shape3DSW::FeatureType support_type_B; + GodotShape3D::FeatureType support_type_B; shape_B->get_supports(transform_B->basis.xform_inv(best_axis).normalized(), max_supports, supports_B, support_count_B, support_type_B); for (int i = 0; i < support_count_B; i++) { supports_B[i] = transform_B->xform(supports_B[i]); @@ -749,7 +748,6 @@ public: } _FORCE_INLINE_ SeparatorAxisTest(const ShapeA *p_shape_A, const Transform3D &p_transform_A, const ShapeB *p_shape_B, const Transform3D &p_transform_B, _CollectorCallback *p_callback, real_t p_margin_A = 0, real_t p_margin_B = 0) { - best_depth = 1e15; shape_A = p_shape_A; shape_B = p_shape_B; transform_A = &p_transform_A; @@ -762,14 +760,14 @@ public: /****** SAT TESTS *******/ -typedef void (*CollisionFunc)(const Shape3DSW *, const Transform3D &, const Shape3DSW *, const Transform3D &, _CollectorCallback *p_callback, real_t, real_t); +typedef void (*CollisionFunc)(const GodotShape3D *, const Transform3D &, const GodotShape3D *, const Transform3D &, _CollectorCallback *p_callback, real_t, real_t); template <bool withMargin> -static void _collision_sphere_sphere(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); - const SphereShape3DSW *sphere_B = static_cast<const SphereShape3DSW *>(p_b); +static void _collision_sphere_sphere(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); + const GodotSphereShape3D *sphere_B = static_cast<const GodotSphereShape3D *>(p_b); - SeparatorAxisTest<SphereShape3DSW, SphereShape3DSW, withMargin> separator(sphere_A, p_transform_a, sphere_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotSphereShape3D, GodotSphereShape3D, withMargin> separator(sphere_A, p_transform_a, sphere_B, p_transform_b, p_collector, p_margin_a, p_margin_b); // previous axis @@ -785,11 +783,11 @@ static void _collision_sphere_sphere(const Shape3DSW *p_a, const Transform3D &p_ } template <bool withMargin> -static void _collision_sphere_box(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); - const BoxShape3DSW *box_B = static_cast<const BoxShape3DSW *>(p_b); +static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); + const GodotBoxShape3D *box_B = static_cast<const GodotBoxShape3D *>(p_b); - SeparatorAxisTest<SphereShape3DSW, BoxShape3DSW, withMargin> separator(sphere_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotSphereShape3D, GodotBoxShape3D, withMargin> separator(sphere_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -836,11 +834,11 @@ static void _collision_sphere_box(const Shape3DSW *p_a, const Transform3D &p_tra } template <bool withMargin> -static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); - const CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b); +static void _collision_sphere_capsule(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); + const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - SeparatorAxisTest<SphereShape3DSW, CapsuleShape3DSW, withMargin> separator(sphere_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotSphereShape3D, GodotCapsuleShape3D, withMargin> separator(sphere_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -878,11 +876,11 @@ static void _collision_sphere_capsule(const Shape3DSW *p_a, const Transform3D &p } template <bool withMargin> -static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); - const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); +static void _collision_sphere_cylinder(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); + const GodotCylinderShape3D *cylinder_B = static_cast<const GodotCylinderShape3D *>(p_b); - SeparatorAxisTest<SphereShape3DSW, CylinderShape3DSW, withMargin> separator(sphere_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotSphereShape3D, GodotCylinderShape3D, withMargin> separator(sphere_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -937,11 +935,11 @@ static void _collision_sphere_cylinder(const Shape3DSW *p_a, const Transform3D & } template <bool withMargin> -static void _collision_sphere_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); - const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); +static void _collision_sphere_convex_polygon(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); + const GodotConvexPolygonShape3D *convex_polygon_B = static_cast<const GodotConvexPolygonShape3D *>(p_b); - SeparatorAxisTest<SphereShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(sphere_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotSphereShape3D, GodotConvexPolygonShape3D, withMargin> separator(sphere_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1000,11 +998,11 @@ static void _collision_sphere_convex_polygon(const Shape3DSW *p_a, const Transfo } template <bool withMargin> -static void _collision_sphere_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const SphereShape3DSW *sphere_A = static_cast<const SphereShape3DSW *>(p_a); - const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); +static void _collision_sphere_face(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotSphereShape3D *sphere_A = static_cast<const GodotSphereShape3D *>(p_a); + const GodotFaceShape3D *face_B = static_cast<const GodotFaceShape3D *>(p_b); - SeparatorAxisTest<SphereShape3DSW, FaceShape3DSW, withMargin> separator(sphere_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotSphereShape3D, GodotFaceShape3D, withMargin> separator(sphere_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); Vector3 vertex[3] = { p_transform_b.xform(face_B->vertex[0]), @@ -1014,7 +1012,7 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform3D &p_tr Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -1041,15 +1039,26 @@ static void _collision_sphere_face(const Shape3DSW *p_a, const Transform3D &p_tr } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } template <bool withMargin> -static void _collision_box_box(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); - const BoxShape3DSW *box_B = static_cast<const BoxShape3DSW *>(p_b); +static void _collision_box_box(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotBoxShape3D *box_A = static_cast<const GodotBoxShape3D *>(p_a); + const GodotBoxShape3D *box_B = static_cast<const GodotBoxShape3D *>(p_b); - SeparatorAxisTest<BoxShape3DSW, BoxShape3DSW, withMargin> separator(box_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotBoxShape3D, GodotBoxShape3D, withMargin> separator(box_A, p_transform_a, box_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1143,11 +1152,11 @@ static void _collision_box_box(const Shape3DSW *p_a, const Transform3D &p_transf } template <bool withMargin> -static void _collision_box_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); - const CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b); +static void _collision_box_capsule(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotBoxShape3D *box_A = static_cast<const GodotBoxShape3D *>(p_a); + const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - SeparatorAxisTest<BoxShape3DSW, CapsuleShape3DSW, withMargin> separator(box_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotBoxShape3D, GodotCapsuleShape3D, withMargin> separator(box_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1195,7 +1204,7 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform3D &p_tr } //Vector3 axis = (point - cyl_axis * cyl_axis.dot(point)).normalized(); - Vector3 axis = Plane(cyl_axis, 0).project(point).normalized(); + Vector3 axis = Plane(cyl_axis).project(point).normalized(); if (!separator.test_axis(axis)) { return; @@ -1241,11 +1250,11 @@ static void _collision_box_capsule(const Shape3DSW *p_a, const Transform3D &p_tr } template <bool withMargin> -static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); - const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); +static void _collision_box_cylinder(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotBoxShape3D *box_A = static_cast<const GodotBoxShape3D *>(p_a); + const GodotCylinderShape3D *cylinder_B = static_cast<const GodotCylinderShape3D *>(p_b); - SeparatorAxisTest<BoxShape3DSW, CylinderShape3DSW, withMargin> separator(box_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotBoxShape3D, GodotCylinderShape3D, withMargin> separator(box_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1304,7 +1313,7 @@ static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform3D &p_t // Points of A, cylinder lateral surface. for (int i = 0; i < 8; i++) { const Vector3 &point = vertices_A[i]; - Vector3 axis = Plane(cyl_axis, 0).project(point).normalized(); + Vector3 axis = Plane(cyl_axis).project(point).normalized(); if (!separator.test_axis(axis)) { return; @@ -1354,11 +1363,11 @@ static void _collision_box_cylinder(const Shape3DSW *p_a, const Transform3D &p_t } template <bool withMargin> -static void _collision_box_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); - const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); +static void _collision_box_convex_polygon(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotBoxShape3D *box_A = static_cast<const GodotBoxShape3D *>(p_a); + const GodotConvexPolygonShape3D *convex_polygon_B = static_cast<const GodotConvexPolygonShape3D *>(p_b); - SeparatorAxisTest<BoxShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(box_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotBoxShape3D, GodotConvexPolygonShape3D, withMargin> separator(box_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1472,11 +1481,11 @@ static void _collision_box_convex_polygon(const Shape3DSW *p_a, const Transform3 } template <bool withMargin> -static void _collision_box_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const BoxShape3DSW *box_A = static_cast<const BoxShape3DSW *>(p_a); - const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); +static void _collision_box_face(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotBoxShape3D *box_A = static_cast<const GodotBoxShape3D *>(p_a); + const GodotFaceShape3D *face_B = static_cast<const GodotFaceShape3D *>(p_b); - SeparatorAxisTest<BoxShape3DSW, FaceShape3DSW, withMargin> separator(box_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotBoxShape3D, GodotFaceShape3D, withMargin> separator(box_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); Vector3 vertex[3] = { p_transform_b.xform(face_B->vertex[0]), @@ -1486,7 +1495,7 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform3D &p_trans Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -1591,15 +1600,26 @@ static void _collision_box_face(const Shape3DSW *p_a, const Transform3D &p_trans } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } template <bool withMargin> -static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); - const CapsuleShape3DSW *capsule_B = static_cast<const CapsuleShape3DSW *>(p_b); +static void _collision_capsule_capsule(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotCapsuleShape3D *capsule_A = static_cast<const GodotCapsuleShape3D *>(p_a); + const GodotCapsuleShape3D *capsule_B = static_cast<const GodotCapsuleShape3D *>(p_b); - SeparatorAxisTest<CapsuleShape3DSW, CapsuleShape3DSW, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotCapsuleShape3D, GodotCapsuleShape3D, withMargin> separator(capsule_A, p_transform_a, capsule_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1659,11 +1679,11 @@ static void _collision_capsule_capsule(const Shape3DSW *p_a, const Transform3D & } template <bool withMargin> -static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); - const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); +static void _collision_capsule_cylinder(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotCapsuleShape3D *capsule_A = static_cast<const GodotCapsuleShape3D *>(p_a); + const GodotCylinderShape3D *cylinder_B = static_cast<const GodotCylinderShape3D *>(p_b); - SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin> separator(capsule_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotCapsuleShape3D, GodotCylinderShape3D, withMargin> separator(capsule_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1710,7 +1730,7 @@ static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform3D return; } - CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CapsuleShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points; + GodotCollisionSolver3D::CallbackResult callback = SeparatorAxisTest<GodotCapsuleShape3D, GodotCylinderShape3D, withMargin>::test_contact_points; // Fallback to generic algorithm to find the best separating axis. if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) { @@ -1721,11 +1741,11 @@ static void _collision_capsule_cylinder(const Shape3DSW *p_a, const Transform3D } template <bool withMargin> -static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); - const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); +static void _collision_capsule_convex_polygon(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotCapsuleShape3D *capsule_A = static_cast<const GodotCapsuleShape3D *>(p_a); + const GodotConvexPolygonShape3D *convex_polygon_B = static_cast<const GodotConvexPolygonShape3D *>(p_b); - SeparatorAxisTest<CapsuleShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(capsule_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotCapsuleShape3D, GodotConvexPolygonShape3D, withMargin> separator(capsule_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1788,11 +1808,11 @@ static void _collision_capsule_convex_polygon(const Shape3DSW *p_a, const Transf } template <bool withMargin> -static void _collision_capsule_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const CapsuleShape3DSW *capsule_A = static_cast<const CapsuleShape3DSW *>(p_a); - const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); +static void _collision_capsule_face(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotCapsuleShape3D *capsule_A = static_cast<const GodotCapsuleShape3D *>(p_a); + const GodotFaceShape3D *face_B = static_cast<const GodotFaceShape3D *>(p_b); - SeparatorAxisTest<CapsuleShape3DSW, FaceShape3DSW, withMargin> separator(capsule_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotCapsuleShape3D, GodotFaceShape3D, withMargin> separator(capsule_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); Vector3 vertex[3] = { p_transform_b.xform(face_B->vertex[0]), @@ -1802,7 +1822,7 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform3D &p_t Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -1858,15 +1878,26 @@ static void _collision_capsule_face(const Shape3DSW *p_a, const Transform3D &p_t } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } template <bool withMargin> -static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); - const CylinderShape3DSW *cylinder_B = static_cast<const CylinderShape3DSW *>(p_b); +static void _collision_cylinder_cylinder(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotCylinderShape3D *cylinder_A = static_cast<const GodotCylinderShape3D *>(p_a); + const GodotCylinderShape3D *cylinder_B = static_cast<const GodotCylinderShape3D *>(p_b); - SeparatorAxisTest<CylinderShape3DSW, CylinderShape3DSW, withMargin> separator(cylinder_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotCylinderShape3D, GodotCylinderShape3D, withMargin> separator(cylinder_A, p_transform_a, cylinder_B, p_transform_b, p_collector, p_margin_a, p_margin_b); Vector3 cylinder_A_axis = p_transform_a.basis.get_axis(1); Vector3 cylinder_B_axis = p_transform_b.basis.get_axis(1); @@ -1905,7 +1936,7 @@ static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform3D return; } - CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, CylinderShape3DSW, withMargin>::test_contact_points; + GodotCollisionSolver3D::CallbackResult callback = SeparatorAxisTest<GodotCylinderShape3D, GodotCylinderShape3D, withMargin>::test_contact_points; // Fallback to generic algorithm to find the best separating axis. if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) { @@ -1916,13 +1947,13 @@ static void _collision_cylinder_cylinder(const Shape3DSW *p_a, const Transform3D } template <bool withMargin> -static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); - const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); +static void _collision_cylinder_convex_polygon(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotCylinderShape3D *cylinder_A = static_cast<const GodotCylinderShape3D *>(p_a); + const GodotConvexPolygonShape3D *convex_polygon_B = static_cast<const GodotConvexPolygonShape3D *>(p_b); - SeparatorAxisTest<CylinderShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(cylinder_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotCylinderShape3D, GodotConvexPolygonShape3D, withMargin> separator(cylinder_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); - CollisionSolver3DSW::CallbackResult callback = SeparatorAxisTest<CylinderShape3DSW, ConvexPolygonShape3DSW, withMargin>::test_contact_points; + GodotCollisionSolver3D::CallbackResult callback = SeparatorAxisTest<GodotCylinderShape3D, GodotConvexPolygonShape3D, withMargin>::test_contact_points; // Fallback to generic algorithm to find the best separating axis. if (!fallback_collision_solver(p_a, p_transform_a, p_b, p_transform_b, callback, &separator, false, p_margin_a, p_margin_b)) { @@ -1933,11 +1964,11 @@ static void _collision_cylinder_convex_polygon(const Shape3DSW *p_a, const Trans } template <bool withMargin> -static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const CylinderShape3DSW *cylinder_A = static_cast<const CylinderShape3DSW *>(p_a); - const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); +static void _collision_cylinder_face(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotCylinderShape3D *cylinder_A = static_cast<const GodotCylinderShape3D *>(p_a); + const GodotFaceShape3D *face_B = static_cast<const GodotFaceShape3D *>(p_b); - SeparatorAxisTest<CylinderShape3DSW, FaceShape3DSW, withMargin> separator(cylinder_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotCylinderShape3D, GodotFaceShape3D, withMargin> separator(cylinder_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -1952,7 +1983,7 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform3D &p_ Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); // Face B normal. - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -1986,7 +2017,7 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform3D &p_ // Points of B, cylinder lateral surface. for (int i = 0; i < 3; i++) { const Vector3 &point = vertex[i]; - Vector3 axis = Plane(cyl_axis, 0).project(point).normalized(); + Vector3 axis = Plane(cyl_axis).project(point).normalized(); if (axis.dot(normal) < 0.0) { axis *= -1.0; } @@ -2034,15 +2065,26 @@ static void _collision_cylinder_face(const Shape3DSW *p_a, const Transform3D &p_ } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } template <bool withMargin> -static void _collision_convex_polygon_convex_polygon(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const ConvexPolygonShape3DSW *convex_polygon_A = static_cast<const ConvexPolygonShape3DSW *>(p_a); - const ConvexPolygonShape3DSW *convex_polygon_B = static_cast<const ConvexPolygonShape3DSW *>(p_b); +static void _collision_convex_polygon_convex_polygon(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotConvexPolygonShape3D *convex_polygon_A = static_cast<const GodotConvexPolygonShape3D *>(p_a); + const GodotConvexPolygonShape3D *convex_polygon_B = static_cast<const GodotConvexPolygonShape3D *>(p_b); - SeparatorAxisTest<ConvexPolygonShape3DSW, ConvexPolygonShape3DSW, withMargin> separator(convex_polygon_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotConvexPolygonShape3D, GodotConvexPolygonShape3D, withMargin> separator(convex_polygon_A, p_transform_a, convex_polygon_B, p_transform_b, p_collector, p_margin_a, p_margin_b); if (!separator.test_previous_axis()) { return; @@ -2151,11 +2193,11 @@ static void _collision_convex_polygon_convex_polygon(const Shape3DSW *p_a, const } template <bool withMargin> -static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform3D &p_transform_a, const Shape3DSW *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { - const ConvexPolygonShape3DSW *convex_polygon_A = static_cast<const ConvexPolygonShape3DSW *>(p_a); - const FaceShape3DSW *face_B = static_cast<const FaceShape3DSW *>(p_b); +static void _collision_convex_polygon_face(const GodotShape3D *p_a, const Transform3D &p_transform_a, const GodotShape3D *p_b, const Transform3D &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + const GodotConvexPolygonShape3D *convex_polygon_A = static_cast<const GodotConvexPolygonShape3D *>(p_a); + const GodotFaceShape3D *face_B = static_cast<const GodotFaceShape3D *>(p_b); - SeparatorAxisTest<ConvexPolygonShape3DSW, FaceShape3DSW, withMargin> separator(convex_polygon_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); + SeparatorAxisTest<GodotConvexPolygonShape3D, GodotFaceShape3D, withMargin> separator(convex_polygon_A, p_transform_a, face_B, p_transform_b, p_collector, p_margin_a, p_margin_b); const Geometry3D::MeshData &mesh = convex_polygon_A->get_mesh(); @@ -2174,7 +2216,7 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform Vector3 normal = (vertex[0] - vertex[2]).cross(vertex[0] - vertex[1]).normalized(); - if (!separator.test_axis(normal, !face_B->backface_collision)) { + if (!separator.test_axis(normal)) { return; } @@ -2266,19 +2308,30 @@ static void _collision_convex_polygon_face(const Shape3DSW *p_a, const Transform } } + if (!face_B->backface_collision) { + if (separator.best_axis.dot(normal) < _BACKFACE_NORMAL_THRESHOLD) { + if (face_B->invert_backface_collision) { + separator.best_axis = separator.best_axis.bounce(normal); + } else { + // Just ignore backface collision. + return; + } + } + } + separator.generate_contacts(); } -bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector3 *r_prev_axis, real_t p_margin_a, real_t p_margin_b) { +bool sat_calculate_penetration(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, GodotCollisionSolver3D::CallbackResult p_result_callback, void *p_userdata, bool p_swap, Vector3 *r_prev_axis, real_t p_margin_a, real_t p_margin_b) { PhysicsServer3D::ShapeType type_A = p_shape_A->get_type(); - ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_PLANE, false); + ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_WORLD_BOUNDARY, false); ERR_FAIL_COND_V(type_A == PhysicsServer3D::SHAPE_SEPARATION_RAY, false); ERR_FAIL_COND_V(p_shape_A->is_concave(), false); PhysicsServer3D::ShapeType type_B = p_shape_B->get_type(); - ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_PLANE, false); + ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_WORLD_BOUNDARY, false); ERR_FAIL_COND_V(type_B == PhysicsServer3D::SHAPE_SEPARATION_RAY, false); ERR_FAIL_COND_V(p_shape_B->is_concave(), false); @@ -2367,8 +2420,8 @@ bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_ callback.collided = false; callback.prev_axis = r_prev_axis; - const Shape3DSW *A = p_shape_A; - const Shape3DSW *B = p_shape_B; + const GodotShape3D *A = p_shape_A; + const GodotShape3D *B = p_shape_B; const Transform3D *transform_A = &p_transform_A; const Transform3D *transform_B = &p_transform_B; real_t margin_A = p_margin_a; diff --git a/servers/physics_3d/collision_solver_3d_sat.h b/servers/physics_3d/godot_collision_solver_3d_sat.h index e50da7b101..069a701cba 100644 --- a/servers/physics_3d/collision_solver_3d_sat.h +++ b/servers/physics_3d/godot_collision_solver_3d_sat.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* collision_solver_3d_sat.h */ +/* godot_collision_solver_3d_sat.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef COLLISION_SOLVER_SAT_H -#define COLLISION_SOLVER_SAT_H +#ifndef GODOT_COLLISION_SOLVER_SAT_H +#define GODOT_COLLISION_SOLVER_SAT_H -#include "collision_solver_3d_sw.h" +#include "godot_collision_solver_3d.h" -bool sat_calculate_penetration(const Shape3DSW *p_shape_A, const Transform3D &p_transform_A, const Shape3DSW *p_shape_B, const Transform3D &p_transform_B, CollisionSolver3DSW::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector3 *r_prev_axis = nullptr, real_t p_margin_a = 0, real_t p_margin_b = 0); +bool sat_calculate_penetration(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, GodotCollisionSolver3D::CallbackResult p_result_callback, void *p_userdata, bool p_swap = false, Vector3 *r_prev_axis = nullptr, real_t p_margin_a = 0, real_t p_margin_b = 0); -#endif // COLLISION_SOLVER_SAT_H +#endif // GODOT_COLLISION_SOLVER_SAT_H diff --git a/servers/physics_3d/constraint_3d_sw.h b/servers/physics_3d/godot_constraint_3d.h index 7b44726ef5..840c81716c 100644 --- a/servers/physics_3d/constraint_3d_sw.h +++ b/servers/physics_3d/godot_constraint_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* constraint_3d_sw.h */ +/* godot_constraint_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,14 +28,14 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef CONSTRAINT_SW_H -#define CONSTRAINT_SW_H +#ifndef GODOT_CONSTRAINT_3D_H +#define GODOT_CONSTRAINT_3D_H -class Body3DSW; -class SoftBody3DSW; +class GodotBody3D; +class GodotSoftBody3D; -class Constraint3DSW { - Body3DSW **_body_ptr; +class GodotConstraint3D { + GodotBody3D **_body_ptr; int _body_count; uint64_t island_step; int priority; @@ -44,7 +44,7 @@ class Constraint3DSW { RID self; protected: - Constraint3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) { + GodotConstraint3D(GodotBody3D **p_body_ptr = nullptr, int p_body_count = 0) { _body_ptr = p_body_ptr; _body_count = p_body_count; island_step = 0; @@ -59,10 +59,10 @@ public: _FORCE_INLINE_ uint64_t get_island_step() const { return island_step; } _FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; } - _FORCE_INLINE_ Body3DSW **get_body_ptr() const { return _body_ptr; } + _FORCE_INLINE_ GodotBody3D **get_body_ptr() const { return _body_ptr; } _FORCE_INLINE_ int get_body_count() const { return _body_count; } - virtual SoftBody3DSW *get_soft_body_ptr(int p_index) const { return nullptr; } + virtual GodotSoftBody3D *get_soft_body_ptr(int p_index) const { return nullptr; } virtual int get_soft_body_count() const { return 0; } _FORCE_INLINE_ void set_priority(int p_priority) { priority = p_priority; } @@ -75,7 +75,7 @@ public: virtual bool pre_solve(real_t p_step) = 0; virtual void solve(real_t p_step) = 0; - virtual ~Constraint3DSW() {} + virtual ~GodotConstraint3D() {} }; -#endif // CONSTRAINT__SW_H +#endif // GODOT_CONSTRAINT_3D_H diff --git a/servers/physics_3d/joints_3d_sw.h b/servers/physics_3d/godot_joint_3d.h index e2514674ea..4086bb53e1 100644 --- a/servers/physics_3d/joints_3d_sw.h +++ b/servers/physics_3d/godot_joint_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* joints_3d_sw.h */ +/* godot_joint_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,13 +28,13 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef JOINTS_SW_H -#define JOINTS_SW_H +#ifndef GODOT_JOINT_3D_H +#define GODOT_JOINT_3D_H -#include "body_3d_sw.h" -#include "constraint_3d_sw.h" +#include "godot_body_3d.h" +#include "godot_constraint_3d.h" -class Joint3DSW : public Constraint3DSW { +class GodotJoint3D : public GodotConstraint3D { protected: bool dynamic_A = false; bool dynamic_B = false; @@ -44,20 +44,20 @@ public: virtual bool pre_solve(real_t p_step) override { return true; } virtual void solve(real_t p_step) override {} - void copy_settings_from(Joint3DSW *p_joint) { + void copy_settings_from(GodotJoint3D *p_joint) { set_self(p_joint->get_self()); set_priority(p_joint->get_priority()); disable_collisions_between_bodies(p_joint->is_disabled_collisions_between_bodies()); } virtual PhysicsServer3D::JointType get_type() const { return PhysicsServer3D::JOINT_TYPE_MAX; } - _FORCE_INLINE_ Joint3DSW(Body3DSW **p_body_ptr = nullptr, int p_body_count = 0) : - Constraint3DSW(p_body_ptr, p_body_count) { + _FORCE_INLINE_ GodotJoint3D(GodotBody3D **p_body_ptr = nullptr, int p_body_count = 0) : + GodotConstraint3D(p_body_ptr, p_body_count) { } - virtual ~Joint3DSW() { + virtual ~GodotJoint3D() { for (int i = 0; i < get_body_count(); i++) { - Body3DSW *body = get_body_ptr()[i]; + GodotBody3D *body = get_body_ptr()[i]; if (body) { body->remove_constraint(this); } @@ -65,4 +65,4 @@ public: } }; -#endif // JOINTS_SW_H +#endif // GODOT_JOINT_3D_H diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp new file mode 100644 index 0000000000..9acae62382 --- /dev/null +++ b/servers/physics_3d/godot_physics_server_3d.cpp @@ -0,0 +1,1740 @@ +/*************************************************************************/ +/* godot_physics_server_3d.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "godot_physics_server_3d.h" + +#include "godot_body_direct_state_3d.h" +#include "godot_broad_phase_3d_bvh.h" +#include "joints/godot_cone_twist_joint_3d.h" +#include "joints/godot_generic_6dof_joint_3d.h" +#include "joints/godot_hinge_joint_3d.h" +#include "joints/godot_pin_joint_3d.h" +#include "joints/godot_slider_joint_3d.h" + +#include "core/debugger/engine_debugger.h" +#include "core/os/os.h" + +#define FLUSH_QUERY_CHECK(m_object) \ + ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead."); + +RID GodotPhysicsServer3D::world_boundary_shape_create() { + GodotShape3D *shape = memnew(GodotWorldBoundaryShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::separation_ray_shape_create() { + GodotShape3D *shape = memnew(GodotSeparationRayShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::sphere_shape_create() { + GodotShape3D *shape = memnew(GodotSphereShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::box_shape_create() { + GodotShape3D *shape = memnew(GodotBoxShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::capsule_shape_create() { + GodotShape3D *shape = memnew(GodotCapsuleShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::cylinder_shape_create() { + GodotShape3D *shape = memnew(GodotCylinderShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::convex_polygon_shape_create() { + GodotShape3D *shape = memnew(GodotConvexPolygonShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::concave_polygon_shape_create() { + GodotShape3D *shape = memnew(GodotConcavePolygonShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::heightmap_shape_create() { + GodotShape3D *shape = memnew(GodotHeightMapShape3D); + RID rid = shape_owner.make_rid(shape); + shape->set_self(rid); + return rid; +} +RID GodotPhysicsServer3D::custom_shape_create() { + ERR_FAIL_V(RID()); +} + +void GodotPhysicsServer3D::shape_set_data(RID p_shape, const Variant &p_data) { + GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + shape->set_data(p_data); +}; + +void GodotPhysicsServer3D::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) { + GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + shape->set_custom_bias(p_bias); +} + +PhysicsServer3D::ShapeType GodotPhysicsServer3D::shape_get_type(RID p_shape) const { + const GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM); + return shape->get_type(); +}; + +Variant GodotPhysicsServer3D::shape_get_data(RID p_shape) const { + const GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND_V(!shape, Variant()); + ERR_FAIL_COND_V(!shape->is_configured(), Variant()); + return shape->get_data(); +}; + +void GodotPhysicsServer3D::shape_set_margin(RID p_shape, real_t p_margin) { +} + +real_t GodotPhysicsServer3D::shape_get_margin(RID p_shape) const { + return 0.0; +} + +real_t GodotPhysicsServer3D::shape_get_custom_solver_bias(RID p_shape) const { + const GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND_V(!shape, 0); + return shape->get_custom_bias(); +} + +RID GodotPhysicsServer3D::space_create() { + GodotSpace3D *space = memnew(GodotSpace3D); + RID id = space_owner.make_rid(space); + space->set_self(id); + RID area_id = area_create(); + GodotArea3D *area = area_owner.get_or_null(area_id); + ERR_FAIL_COND_V(!area, RID()); + space->set_default_area(area); + area->set_space(space); + area->set_priority(-1); + RID sgb = body_create(); + body_set_space(sgb, id); + body_set_mode(sgb, BODY_MODE_STATIC); + space->set_static_global_body(sgb); + + return id; +}; + +void GodotPhysicsServer3D::space_set_active(RID p_space, bool p_active) { + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + if (p_active) { + active_spaces.insert(space); + } else { + active_spaces.erase(space); + } +} + +bool GodotPhysicsServer3D::space_is_active(RID p_space) const { + const GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, false); + + return active_spaces.has(space); +} + +void GodotPhysicsServer3D::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + + space->set_param(p_param, p_value); +} + +real_t GodotPhysicsServer3D::space_get_param(RID p_space, SpaceParameter p_param) const { + const GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, 0); + return space->get_param(p_param); +} + +PhysicsDirectSpaceState3D *GodotPhysicsServer3D::space_get_direct_state(RID p_space) { + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, nullptr); + ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification."); + + return space->get_direct_state(); +} + +void GodotPhysicsServer3D::space_set_debug_contacts(RID p_space, int p_max_contacts) { + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + space->set_debug_contacts(p_max_contacts); +} + +Vector<Vector3> GodotPhysicsServer3D::space_get_contacts(RID p_space) const { + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, Vector<Vector3>()); + return space->get_debug_contacts(); +} + +int GodotPhysicsServer3D::space_get_contact_count(RID p_space) const { + GodotSpace3D *space = space_owner.get_or_null(p_space); + ERR_FAIL_COND_V(!space, 0); + return space->get_debug_contact_count(); +} + +RID GodotPhysicsServer3D::area_create() { + GodotArea3D *area = memnew(GodotArea3D); + RID rid = area_owner.make_rid(area); + area->set_self(rid); + return rid; +} + +void GodotPhysicsServer3D::area_set_space(RID p_area, RID p_space) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + GodotSpace3D *space = nullptr; + if (p_space.is_valid()) { + space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + } + + if (area->get_space() == space) { + return; //pointless + } + + area->clear_constraints(); + area->set_space(space); +} + +RID GodotPhysicsServer3D::area_get_space(RID p_area) const { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, RID()); + + GodotSpace3D *space = area->get_space(); + if (!space) { + return RID(); + } + return space->get_self(); +} + +void GodotPhysicsServer3D::area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform, bool p_disabled) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + + area->add_shape(shape, p_transform, p_disabled); +} + +void GodotPhysicsServer3D::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + ERR_FAIL_COND(!shape->is_configured()); + + area->set_shape(p_shape_idx, shape); +} + +void GodotPhysicsServer3D::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_shape_transform(p_shape_idx, p_transform); +} + +int GodotPhysicsServer3D::area_get_shape_count(RID p_area) const { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, -1); + + return area->get_shape_count(); +} + +RID GodotPhysicsServer3D::area_get_shape(RID p_area, int p_shape_idx) const { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, RID()); + + GodotShape3D *shape = area->get_shape(p_shape_idx); + ERR_FAIL_COND_V(!shape, RID()); + + return shape->get_self(); +} + +Transform3D GodotPhysicsServer3D::area_get_shape_transform(RID p_area, int p_shape_idx) const { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, Transform3D()); + + return area->get_shape_transform(p_shape_idx); +} + +void GodotPhysicsServer3D::area_remove_shape(RID p_area, int p_shape_idx) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->remove_shape(p_shape_idx); +} + +void GodotPhysicsServer3D::area_clear_shapes(RID p_area) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + while (area->get_shape_count()) { + area->remove_shape(0); + } +} + +void GodotPhysicsServer3D::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + ERR_FAIL_INDEX(p_shape_idx, area->get_shape_count()); + FLUSH_QUERY_CHECK(area); + area->set_shape_disabled(p_shape_idx, p_disabled); +} + +void GodotPhysicsServer3D::area_attach_object_instance_id(RID p_area, ObjectID p_id) { + if (space_owner.owns(p_area)) { + GodotSpace3D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + area->set_instance_id(p_id); +} + +ObjectID GodotPhysicsServer3D::area_get_object_instance_id(RID p_area) const { + if (space_owner.owns(p_area)) { + GodotSpace3D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, ObjectID()); + return area->get_instance_id(); +} + +void GodotPhysicsServer3D::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) { + if (space_owner.owns(p_area)) { + GodotSpace3D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + area->set_param(p_param, p_value); +}; + +void GodotPhysicsServer3D::area_set_transform(RID p_area, const Transform3D &p_transform) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + area->set_transform(p_transform); +}; + +Variant GodotPhysicsServer3D::area_get_param(RID p_area, AreaParameter p_param) const { + if (space_owner.owns(p_area)) { + GodotSpace3D *space = space_owner.get_or_null(p_area); + p_area = space->get_default_area()->get_self(); + } + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, Variant()); + + return area->get_param(p_param); +}; + +Transform3D GodotPhysicsServer3D::area_get_transform(RID p_area) const { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND_V(!area, Transform3D()); + + return area->get_transform(); +}; + +void GodotPhysicsServer3D::area_set_collision_layer(RID p_area, uint32_t p_layer) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_collision_layer(p_layer); +} + +void GodotPhysicsServer3D::area_set_collision_mask(RID p_area, uint32_t p_mask) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_collision_mask(p_mask); +} + +void GodotPhysicsServer3D::area_set_monitorable(RID p_area, bool p_monitorable) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + FLUSH_QUERY_CHECK(area); + + area->set_monitorable(p_monitorable); +} + +void GodotPhysicsServer3D::area_set_monitor_callback(RID p_area, const Callable &p_callback) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_monitor_callback(p_callback.is_valid() ? p_callback : Callable()); +} + +void GodotPhysicsServer3D::area_set_ray_pickable(RID p_area, bool p_enable) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_ray_pickable(p_enable); +} + +void GodotPhysicsServer3D::area_set_area_monitor_callback(RID p_area, const Callable &p_callback) { + GodotArea3D *area = area_owner.get_or_null(p_area); + ERR_FAIL_COND(!area); + + area->set_area_monitor_callback(p_callback.is_valid() ? p_callback : Callable()); +} + +/* BODY API */ + +RID GodotPhysicsServer3D::body_create() { + GodotBody3D *body = memnew(GodotBody3D); + RID rid = body_owner.make_rid(body); + body->set_self(rid); + return rid; +}; + +void GodotPhysicsServer3D::body_set_space(RID p_body, RID p_space) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + GodotSpace3D *space = nullptr; + if (p_space.is_valid()) { + space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + } + + if (body->get_space() == space) { + return; //pointless + } + + body->clear_constraint_map(); + body->set_space(space); +}; + +RID GodotPhysicsServer3D::body_get_space(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, RID()); + + GodotSpace3D *space = body->get_space(); + if (!space) { + return RID(); + } + return space->get_self(); +}; + +void GodotPhysicsServer3D::body_set_mode(RID p_body, BodyMode p_mode) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_mode(p_mode); +}; + +PhysicsServer3D::BodyMode GodotPhysicsServer3D::body_get_mode(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, BODY_MODE_STATIC); + + return body->get_mode(); +}; + +void GodotPhysicsServer3D::body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform, bool p_disabled) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + + body->add_shape(shape, p_transform, p_disabled); +} + +void GodotPhysicsServer3D::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + GodotShape3D *shape = shape_owner.get_or_null(p_shape); + ERR_FAIL_COND(!shape); + ERR_FAIL_COND(!shape->is_configured()); + + body->set_shape(p_shape_idx, shape); +} +void GodotPhysicsServer3D::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_shape_transform(p_shape_idx, p_transform); +} + +int GodotPhysicsServer3D::body_get_shape_count(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, -1); + + return body->get_shape_count(); +} + +RID GodotPhysicsServer3D::body_get_shape(RID p_body, int p_shape_idx) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, RID()); + + GodotShape3D *shape = body->get_shape(p_shape_idx); + ERR_FAIL_COND_V(!shape, RID()); + + return shape->get_self(); +} + +void GodotPhysicsServer3D::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); + FLUSH_QUERY_CHECK(body); + + body->set_shape_disabled(p_shape_idx, p_disabled); +} + +Transform3D GodotPhysicsServer3D::body_get_shape_transform(RID p_body, int p_shape_idx) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, Transform3D()); + + return body->get_shape_transform(p_shape_idx); +} + +void GodotPhysicsServer3D::body_remove_shape(RID p_body, int p_shape_idx) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->remove_shape(p_shape_idx); +} + +void GodotPhysicsServer3D::body_clear_shapes(RID p_body) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + while (body->get_shape_count()) { + body->remove_shape(0); + } +} + +void GodotPhysicsServer3D::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_continuous_collision_detection(p_enable); +} + +bool GodotPhysicsServer3D::body_is_continuous_collision_detection_enabled(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, false); + + return body->is_continuous_collision_detection_enabled(); +} + +void GodotPhysicsServer3D::body_set_collision_layer(RID p_body, uint32_t p_layer) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_layer(p_layer); +} + +uint32_t GodotPhysicsServer3D::body_get_collision_layer(RID p_body) const { + const GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_layer(); +} + +void GodotPhysicsServer3D::body_set_collision_mask(RID p_body, uint32_t p_mask) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_collision_mask(p_mask); +} + +uint32_t GodotPhysicsServer3D::body_get_collision_mask(RID p_body) const { + const GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_collision_mask(); +} + +void GodotPhysicsServer3D::body_attach_object_instance_id(RID p_body, ObjectID p_id) { + GodotBody3D *body = body_owner.get_or_null(p_body); + if (body) { + body->set_instance_id(p_id); + return; + } + + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + if (soft_body) { + soft_body->set_instance_id(p_id); + return; + } + + ERR_FAIL_MSG("Invalid ID."); +}; + +ObjectID GodotPhysicsServer3D::body_get_object_instance_id(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, ObjectID()); + + return body->get_instance_id(); +}; + +void GodotPhysicsServer3D::body_set_user_flags(RID p_body, uint32_t p_flags) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); +}; + +uint32_t GodotPhysicsServer3D::body_get_user_flags(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return 0; +}; + +void GodotPhysicsServer3D::body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_param(p_param, p_value); +}; + +Variant GodotPhysicsServer3D::body_get_param(RID p_body, BodyParameter p_param) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + + return body->get_param(p_param); +}; + +void GodotPhysicsServer3D::body_reset_mass_properties(RID p_body) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + return body->reset_mass_properties(); +} + +void GodotPhysicsServer3D::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_state(p_state, p_variant); +}; + +Variant GodotPhysicsServer3D::body_get_state(RID p_body, BodyState p_state) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, Variant()); + + return body->get_state(p_state); +}; + +void GodotPhysicsServer3D::body_set_applied_force(RID p_body, const Vector3 &p_force) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_applied_force(p_force); + body->wakeup(); +}; + +Vector3 GodotPhysicsServer3D::body_get_applied_force(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, Vector3()); + return body->get_applied_force(); +}; + +void GodotPhysicsServer3D::body_set_applied_torque(RID p_body, const Vector3 &p_torque) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_applied_torque(p_torque); + body->wakeup(); +}; + +Vector3 GodotPhysicsServer3D::body_get_applied_torque(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, Vector3()); + + return body->get_applied_torque(); +}; + +void GodotPhysicsServer3D::body_add_central_force(RID p_body, const Vector3 &p_force) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->add_central_force(p_force); + body->wakeup(); +} + +void GodotPhysicsServer3D::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->add_force(p_force, p_position); + body->wakeup(); +}; + +void GodotPhysicsServer3D::body_add_torque(RID p_body, const Vector3 &p_torque) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->add_torque(p_torque); + body->wakeup(); +}; + +void GodotPhysicsServer3D::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + body->apply_central_impulse(p_impulse); + body->wakeup(); +} + +void GodotPhysicsServer3D::body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + body->apply_impulse(p_impulse, p_position); + body->wakeup(); +}; + +void GodotPhysicsServer3D::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + body->apply_torque_impulse(p_impulse); + body->wakeup(); +}; + +void GodotPhysicsServer3D::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + Vector3 v = body->get_linear_velocity(); + Vector3 axis = p_axis_velocity.normalized(); + v -= axis * axis.dot(v); + v += p_axis_velocity; + body->set_linear_velocity(v); + body->wakeup(); +}; + +void GodotPhysicsServer3D::body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_axis_lock(p_axis, p_lock); + body->wakeup(); +} + +bool GodotPhysicsServer3D::body_is_axis_locked(RID p_body, BodyAxis p_axis) const { + const GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + return body->is_axis_locked(p_axis); +} + +void GodotPhysicsServer3D::body_add_collision_exception(RID p_body, RID p_body_b) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->add_exception(p_body_b); + body->wakeup(); +}; + +void GodotPhysicsServer3D::body_remove_collision_exception(RID p_body, RID p_body_b) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->remove_exception(p_body_b); + body->wakeup(); +}; + +void GodotPhysicsServer3D::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + for (int i = 0; i < body->get_exceptions().size(); i++) { + p_exceptions->push_back(body->get_exceptions()[i]); + } +}; + +void GodotPhysicsServer3D::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); +}; + +real_t GodotPhysicsServer3D::body_get_contacts_reported_depth_threshold(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, 0); + return 0; +}; + +void GodotPhysicsServer3D::body_set_omit_force_integration(RID p_body, bool p_omit) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + + body->set_omit_force_integration(p_omit); +}; + +bool GodotPhysicsServer3D::body_is_omitting_force_integration(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, false); + return body->get_omit_force_integration(); +}; + +void GodotPhysicsServer3D::body_set_max_contacts_reported(RID p_body, int p_contacts) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_max_contacts_reported(p_contacts); +} + +int GodotPhysicsServer3D::body_get_max_contacts_reported(RID p_body) const { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, -1); + return body->get_max_contacts_reported(); +} + +void GodotPhysicsServer3D::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_state_sync_callback(p_instance, p_callback); +} + +void GodotPhysicsServer3D::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_force_integration_callback(p_callable, p_udata); +} + +void GodotPhysicsServer3D::body_set_ray_pickable(RID p_body, bool p_enable) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND(!body); + body->set_ray_pickable(p_enable); +} + +bool GodotPhysicsServer3D::body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result) { + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!body, false); + ERR_FAIL_COND_V(!body->get_space(), false); + ERR_FAIL_COND_V(body->get_space()->is_locked(), false); + + _update_shapes(); + + return body->get_space()->test_body_motion(body, p_parameters, r_result); +} + +PhysicsDirectBodyState3D *GodotPhysicsServer3D::body_get_direct_state(RID p_body) { + ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); + + if (!body_owner.owns(p_body)) { + return nullptr; + } + + GodotBody3D *body = body_owner.get_or_null(p_body); + ERR_FAIL_NULL_V(body, nullptr); + + if (!body->get_space()) { + return nullptr; + } + + ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); + + return body->get_direct_state(); +} + +/* SOFT BODY */ + +RID GodotPhysicsServer3D::soft_body_create() { + GodotSoftBody3D *soft_body = memnew(GodotSoftBody3D); + RID rid = soft_body_owner.make_rid(soft_body); + soft_body->set_self(rid); + return rid; +} + +void GodotPhysicsServer3D::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->update_rendering_server(p_rendering_server_handler); +} + +void GodotPhysicsServer3D::soft_body_set_space(RID p_body, RID p_space) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + GodotSpace3D *space = nullptr; + if (p_space.is_valid()) { + space = space_owner.get_or_null(p_space); + ERR_FAIL_COND(!space); + } + + if (soft_body->get_space() == space) { + return; + } + + soft_body->set_space(space); +} + +RID GodotPhysicsServer3D::soft_body_get_space(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, RID()); + + GodotSpace3D *space = soft_body->get_space(); + if (!space) { + return RID(); + } + return space->get_self(); +} + +void GodotPhysicsServer3D::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_collision_layer(p_layer); +} + +uint32_t GodotPhysicsServer3D::soft_body_get_collision_layer(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, 0); + + return soft_body->get_collision_layer(); +} + +void GodotPhysicsServer3D::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_collision_mask(p_mask); +} + +uint32_t GodotPhysicsServer3D::soft_body_get_collision_mask(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, 0); + + return soft_body->get_collision_mask(); +} + +void GodotPhysicsServer3D::soft_body_add_collision_exception(RID p_body, RID p_body_b) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->add_exception(p_body_b); +} + +void GodotPhysicsServer3D::soft_body_remove_collision_exception(RID p_body, RID p_body_b) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->remove_exception(p_body_b); +} + +void GodotPhysicsServer3D::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + for (int i = 0; i < soft_body->get_exceptions().size(); i++) { + p_exceptions->push_back(soft_body->get_exceptions()[i]); + } +} + +void GodotPhysicsServer3D::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_state(p_state, p_variant); +} + +Variant GodotPhysicsServer3D::soft_body_get_state(RID p_body, BodyState p_state) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, Variant()); + + return soft_body->get_state(p_state); +} + +void GodotPhysicsServer3D::soft_body_set_transform(RID p_body, const Transform3D &p_transform) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_state(BODY_STATE_TRANSFORM, p_transform); +} + +void GodotPhysicsServer3D::soft_body_set_ray_pickable(RID p_body, bool p_enable) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_ray_pickable(p_enable); +} + +void GodotPhysicsServer3D::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_iteration_count(p_simulation_precision); +} + +int GodotPhysicsServer3D::soft_body_get_simulation_precision(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, 0.f); + + return soft_body->get_iteration_count(); +} + +void GodotPhysicsServer3D::soft_body_set_total_mass(RID p_body, real_t p_total_mass) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_total_mass(p_total_mass); +} + +real_t GodotPhysicsServer3D::soft_body_get_total_mass(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, 0.f); + + return soft_body->get_total_mass(); +} + +void GodotPhysicsServer3D::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_linear_stiffness(p_stiffness); +} + +real_t GodotPhysicsServer3D::soft_body_get_linear_stiffness(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, 0.f); + + return soft_body->get_linear_stiffness(); +} + +void GodotPhysicsServer3D::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_pressure_coefficient(p_pressure_coefficient); +} + +real_t GodotPhysicsServer3D::soft_body_get_pressure_coefficient(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, 0.f); + + return soft_body->get_pressure_coefficient(); +} + +void GodotPhysicsServer3D::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_damping_coefficient(p_damping_coefficient); +} + +real_t GodotPhysicsServer3D::soft_body_get_damping_coefficient(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, 0.f); + + return soft_body->get_damping_coefficient(); +} + +void GodotPhysicsServer3D::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_drag_coefficient(p_drag_coefficient); +} + +real_t GodotPhysicsServer3D::soft_body_get_drag_coefficient(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, 0.f); + + return soft_body->get_drag_coefficient(); +} + +void GodotPhysicsServer3D::soft_body_set_mesh(RID p_body, RID p_mesh) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_mesh(p_mesh); +} + +AABB GodotPhysicsServer3D::soft_body_get_bounds(RID p_body) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, AABB()); + + return soft_body->get_bounds(); +} + +void GodotPhysicsServer3D::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->set_vertex_position(p_point_index, p_global_position); +} + +Vector3 GodotPhysicsServer3D::soft_body_get_point_global_position(RID p_body, int p_point_index) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, Vector3()); + + return soft_body->get_vertex_position(p_point_index); +} + +void GodotPhysicsServer3D::soft_body_remove_all_pinned_points(RID p_body) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + soft_body->unpin_all_vertices(); +} + +void GodotPhysicsServer3D::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND(!soft_body); + + if (p_pin) { + soft_body->pin_vertex(p_point_index); + } else { + soft_body->unpin_vertex(p_point_index); + } +} + +bool GodotPhysicsServer3D::soft_body_is_point_pinned(RID p_body, int p_point_index) const { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_body); + ERR_FAIL_COND_V(!soft_body, false); + + return soft_body->is_vertex_pinned(p_point_index); +} + +/* JOINT API */ + +RID GodotPhysicsServer3D::joint_create() { + GodotJoint3D *joint = memnew(GodotJoint3D); + RID rid = joint_owner.make_rid(joint); + joint->set_self(rid); + return rid; +} + +void GodotPhysicsServer3D::joint_clear(RID p_joint) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + if (joint->get_type() != JOINT_TYPE_MAX) { + GodotJoint3D *empty_joint = memnew(GodotJoint3D); + empty_joint->copy_settings_from(joint); + + joint_owner.replace(p_joint, empty_joint); + memdelete(joint); + } +} + +void GodotPhysicsServer3D::joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) { + GodotBody3D *body_A = body_owner.get_or_null(p_body_A); + ERR_FAIL_COND(!body_A); + + if (!p_body_B.is_valid()) { + ERR_FAIL_COND(!body_A->get_space()); + p_body_B = body_A->get_space()->get_static_global_body(); + } + + GodotBody3D *body_B = body_owner.get_or_null(p_body_B); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); + + GodotJoint3D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint3D *joint = memnew(GodotPinJoint3D(body_A, p_local_A, body_B, p_local_B)); + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer3D::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); + GodotPinJoint3D *pin_joint = static_cast<GodotPinJoint3D *>(joint); + pin_joint->set_param(p_param, p_value); +} + +real_t GodotPhysicsServer3D::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, 0); + GodotPinJoint3D *pin_joint = static_cast<GodotPinJoint3D *>(joint); + return pin_joint->get_param(p_param); +} + +void GodotPhysicsServer3D::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); + GodotPinJoint3D *pin_joint = static_cast<GodotPinJoint3D *>(joint); + pin_joint->set_pos_a(p_A); +} + +Vector3 GodotPhysicsServer3D::pin_joint_get_local_a(RID p_joint) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, Vector3()); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, Vector3()); + GodotPinJoint3D *pin_joint = static_cast<GodotPinJoint3D *>(joint); + return pin_joint->get_position_a(); +} + +void GodotPhysicsServer3D::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); + GodotPinJoint3D *pin_joint = static_cast<GodotPinJoint3D *>(joint); + pin_joint->set_pos_b(p_B); +} + +Vector3 GodotPhysicsServer3D::pin_joint_get_local_b(RID p_joint) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, Vector3()); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, Vector3()); + GodotPinJoint3D *pin_joint = static_cast<GodotPinJoint3D *>(joint); + return pin_joint->get_position_b(); +} + +void GodotPhysicsServer3D::joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_frame_A, RID p_body_B, const Transform3D &p_frame_B) { + GodotBody3D *body_A = body_owner.get_or_null(p_body_A); + ERR_FAIL_COND(!body_A); + + if (!p_body_B.is_valid()) { + ERR_FAIL_COND(!body_A->get_space()); + p_body_B = body_A->get_space()->get_static_global_body(); + } + + GodotBody3D *body_B = body_owner.get_or_null(p_body_B); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); + + GodotJoint3D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint3D *joint = memnew(GodotHingeJoint3D(body_A, body_B, p_frame_A, p_frame_B)); + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer3D::joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) { + GodotBody3D *body_A = body_owner.get_or_null(p_body_A); + ERR_FAIL_COND(!body_A); + + if (!p_body_B.is_valid()) { + ERR_FAIL_COND(!body_A->get_space()); + p_body_B = body_A->get_space()->get_static_global_body(); + } + + GodotBody3D *body_B = body_owner.get_or_null(p_body_B); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); + + GodotJoint3D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint3D *joint = memnew(GodotHingeJoint3D(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B)); + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer3D::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_HINGE); + GodotHingeJoint3D *hinge_joint = static_cast<GodotHingeJoint3D *>(joint); + hinge_joint->set_param(p_param, p_value); +} + +real_t GodotPhysicsServer3D::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_HINGE, 0); + GodotHingeJoint3D *hinge_joint = static_cast<GodotHingeJoint3D *>(joint); + return hinge_joint->get_param(p_param); +} + +void GodotPhysicsServer3D::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_HINGE); + GodotHingeJoint3D *hinge_joint = static_cast<GodotHingeJoint3D *>(joint); + hinge_joint->set_flag(p_flag, p_value); +} + +bool GodotPhysicsServer3D::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, false); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_HINGE, false); + GodotHingeJoint3D *hinge_joint = static_cast<GodotHingeJoint3D *>(joint); + return hinge_joint->get_flag(p_flag); +} + +void GodotPhysicsServer3D::joint_set_solver_priority(RID p_joint, int p_priority) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + joint->set_priority(p_priority); +} + +int GodotPhysicsServer3D::joint_get_solver_priority(RID p_joint) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, 0); + return joint->get_priority(); +} + +void GodotPhysicsServer3D::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + + joint->disable_collisions_between_bodies(p_disable); + + if (2 == joint->get_body_count()) { + GodotBody3D *body_a = *joint->get_body_ptr(); + GodotBody3D *body_b = *(joint->get_body_ptr() + 1); + + if (p_disable) { + body_add_collision_exception(body_a->get_self(), body_b->get_self()); + body_add_collision_exception(body_b->get_self(), body_a->get_self()); + } else { + body_remove_collision_exception(body_a->get_self(), body_b->get_self()); + body_remove_collision_exception(body_b->get_self(), body_a->get_self()); + } + } +} + +bool GodotPhysicsServer3D::joint_is_disabled_collisions_between_bodies(RID p_joint) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, true); + + return joint->is_disabled_collisions_between_bodies(); +} + +GodotPhysicsServer3D::JointType GodotPhysicsServer3D::joint_get_type(RID p_joint) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN); + return joint->get_type(); +} + +void GodotPhysicsServer3D::joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { + GodotBody3D *body_A = body_owner.get_or_null(p_body_A); + ERR_FAIL_COND(!body_A); + + if (!p_body_B.is_valid()) { + ERR_FAIL_COND(!body_A->get_space()); + p_body_B = body_A->get_space()->get_static_global_body(); + } + + GodotBody3D *body_B = body_owner.get_or_null(p_body_B); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); + + GodotJoint3D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint3D *joint = memnew(GodotSliderJoint3D(body_A, body_B, p_local_frame_A, p_local_frame_B)); + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer3D::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_SLIDER); + GodotSliderJoint3D *slider_joint = static_cast<GodotSliderJoint3D *>(joint); + slider_joint->set_param(p_param, p_value); +} + +real_t GodotPhysicsServer3D::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_CONE_TWIST, 0); + GodotSliderJoint3D *slider_joint = static_cast<GodotSliderJoint3D *>(joint); + return slider_joint->get_param(p_param); +} + +void GodotPhysicsServer3D::joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { + GodotBody3D *body_A = body_owner.get_or_null(p_body_A); + ERR_FAIL_COND(!body_A); + + if (!p_body_B.is_valid()) { + ERR_FAIL_COND(!body_A->get_space()); + p_body_B = body_A->get_space()->get_static_global_body(); + } + + GodotBody3D *body_B = body_owner.get_or_null(p_body_B); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); + + GodotJoint3D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint3D *joint = memnew(GodotConeTwistJoint3D(body_A, body_B, p_local_frame_A, p_local_frame_B)); + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer3D::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_CONE_TWIST); + GodotConeTwistJoint3D *cone_twist_joint = static_cast<GodotConeTwistJoint3D *>(joint); + cone_twist_joint->set_param(p_param, p_value); +} + +real_t GodotPhysicsServer3D::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_CONE_TWIST, 0); + GodotConeTwistJoint3D *cone_twist_joint = static_cast<GodotConeTwistJoint3D *>(joint); + return cone_twist_joint->get_param(p_param); +} + +void GodotPhysicsServer3D::joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { + GodotBody3D *body_A = body_owner.get_or_null(p_body_A); + ERR_FAIL_COND(!body_A); + + if (!p_body_B.is_valid()) { + ERR_FAIL_COND(!body_A->get_space()); + p_body_B = body_A->get_space()->get_static_global_body(); + } + + GodotBody3D *body_B = body_owner.get_or_null(p_body_B); + ERR_FAIL_COND(!body_B); + + ERR_FAIL_COND(body_A == body_B); + + GodotJoint3D *prev_joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(prev_joint == nullptr); + + GodotJoint3D *joint = memnew(GodotGeneric6DOFJoint3D(body_A, body_B, p_local_frame_A, p_local_frame_B, true)); + + joint->copy_settings_from(prev_joint); + joint_owner.replace(p_joint, joint); + memdelete(prev_joint); +} + +void GodotPhysicsServer3D::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF); + GodotGeneric6DOFJoint3D *generic_6dof_joint = static_cast<GodotGeneric6DOFJoint3D *>(joint); + generic_6dof_joint->set_param(p_axis, p_param, p_value); +} + +real_t GodotPhysicsServer3D::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, 0); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, 0); + GodotGeneric6DOFJoint3D *generic_6dof_joint = static_cast<GodotGeneric6DOFJoint3D *>(joint); + return generic_6dof_joint->get_param(p_axis, p_param); +} + +void GodotPhysicsServer3D::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND(!joint); + ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF); + GodotGeneric6DOFJoint3D *generic_6dof_joint = static_cast<GodotGeneric6DOFJoint3D *>(joint); + generic_6dof_joint->set_flag(p_axis, p_flag, p_enable); +} + +bool GodotPhysicsServer3D::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) const { + GodotJoint3D *joint = joint_owner.get_or_null(p_joint); + ERR_FAIL_COND_V(!joint, false); + ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, false); + GodotGeneric6DOFJoint3D *generic_6dof_joint = static_cast<GodotGeneric6DOFJoint3D *>(joint); + return generic_6dof_joint->get_flag(p_axis, p_flag); +} + +void GodotPhysicsServer3D::free(RID p_rid) { + _update_shapes(); //just in case + + if (shape_owner.owns(p_rid)) { + GodotShape3D *shape = shape_owner.get_or_null(p_rid); + + while (shape->get_owners().size()) { + GodotShapeOwner3D *so = shape->get_owners().front()->key(); + so->remove_shape(shape); + } + + shape_owner.free(p_rid); + memdelete(shape); + } else if (body_owner.owns(p_rid)) { + GodotBody3D *body = body_owner.get_or_null(p_rid); + + /* + if (body->get_state_query()) + _clear_query(body->get_state_query()); + + if (body->get_direct_state_query()) + _clear_query(body->get_direct_state_query()); + */ + + body->set_space(nullptr); + + while (body->get_shape_count()) { + body->remove_shape(0); + } + + body_owner.free(p_rid); + memdelete(body); + } else if (soft_body_owner.owns(p_rid)) { + GodotSoftBody3D *soft_body = soft_body_owner.get_or_null(p_rid); + + soft_body->set_space(nullptr); + + soft_body_owner.free(p_rid); + memdelete(soft_body); + } else if (area_owner.owns(p_rid)) { + GodotArea3D *area = area_owner.get_or_null(p_rid); + + /* + if (area->get_monitor_query()) + _clear_query(area->get_monitor_query()); + */ + + area->set_space(nullptr); + + while (area->get_shape_count()) { + area->remove_shape(0); + } + + area_owner.free(p_rid); + memdelete(area); + } else if (space_owner.owns(p_rid)) { + GodotSpace3D *space = space_owner.get_or_null(p_rid); + + while (space->get_objects().size()) { + GodotCollisionObject3D *co = (GodotCollisionObject3D *)space->get_objects().front()->get(); + co->set_space(nullptr); + } + + active_spaces.erase(space); + free(space->get_default_area()->get_self()); + free(space->get_static_global_body()); + + space_owner.free(p_rid); + memdelete(space); + } else if (joint_owner.owns(p_rid)) { + GodotJoint3D *joint = joint_owner.get_or_null(p_rid); + + joint_owner.free(p_rid); + memdelete(joint); + + } else { + ERR_FAIL_MSG("Invalid ID."); + } +}; + +void GodotPhysicsServer3D::set_active(bool p_active) { + active = p_active; +}; + +void GodotPhysicsServer3D::set_collision_iterations(int p_iterations) { + iterations = p_iterations; +}; + +void GodotPhysicsServer3D::init() { + iterations = 8; // 8? + stepper = memnew(GodotStep3D); +}; + +void GodotPhysicsServer3D::step(real_t p_step) { +#ifndef _3D_DISABLED + + if (!active) { + return; + } + + _update_shapes(); + + island_count = 0; + active_objects = 0; + collision_pairs = 0; + for (Set<const GodotSpace3D *>::Element *E = active_spaces.front(); E; E = E->next()) { + stepper->step((GodotSpace3D *)E->get(), p_step, iterations); + island_count += E->get()->get_island_count(); + active_objects += E->get()->get_active_objects(); + collision_pairs += E->get()->get_collision_pairs(); + } +#endif +} + +void GodotPhysicsServer3D::sync() { + doing_sync = true; +}; + +void GodotPhysicsServer3D::flush_queries() { +#ifndef _3D_DISABLED + + if (!active) { + return; + } + + flushing_queries = true; + + uint64_t time_beg = OS::get_singleton()->get_ticks_usec(); + + for (Set<const GodotSpace3D *>::Element *E = active_spaces.front(); E; E = E->next()) { + GodotSpace3D *space = (GodotSpace3D *)E->get(); + space->call_queries(); + } + + flushing_queries = false; + + if (EngineDebugger::is_profiling("servers")) { + uint64_t total_time[GodotSpace3D::ELAPSED_TIME_MAX]; + static const char *time_name[GodotSpace3D::ELAPSED_TIME_MAX] = { + "integrate_forces", + "generate_islands", + "setup_constraints", + "solve_constraints", + "integrate_velocities" + }; + + for (int i = 0; i < GodotSpace3D::ELAPSED_TIME_MAX; i++) { + total_time[i] = 0; + } + + for (Set<const GodotSpace3D *>::Element *E = active_spaces.front(); E; E = E->next()) { + for (int i = 0; i < GodotSpace3D::ELAPSED_TIME_MAX; i++) { + total_time[i] += E->get()->get_elapsed_time(GodotSpace3D::ElapsedTime(i)); + } + } + + Array values; + values.resize(GodotSpace3D::ELAPSED_TIME_MAX * 2); + for (int i = 0; i < GodotSpace3D::ELAPSED_TIME_MAX; i++) { + values[i * 2 + 0] = time_name[i]; + values[i * 2 + 1] = USEC_TO_SEC(total_time[i]); + } + values.push_back("flush_queries"); + values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg)); + + values.push_front("physics"); + EngineDebugger::profiler_add_frame_data("servers", values); + } +#endif +}; + +void GodotPhysicsServer3D::end_sync() { + doing_sync = false; +}; + +void GodotPhysicsServer3D::finish() { + memdelete(stepper); +}; + +int GodotPhysicsServer3D::get_process_info(ProcessInfo p_info) { + switch (p_info) { + case INFO_ACTIVE_OBJECTS: { + return active_objects; + } break; + case INFO_COLLISION_PAIRS: { + return collision_pairs; + } break; + case INFO_ISLAND_COUNT: { + return island_count; + } break; + } + + return 0; +} + +void GodotPhysicsServer3D::_update_shapes() { + while (pending_shape_update_list.first()) { + pending_shape_update_list.first()->self()->_shape_changed(); + pending_shape_update_list.remove(pending_shape_update_list.first()); + } +} + +void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { + CollCbkData *cbk = (CollCbkData *)p_userdata; + + if (cbk->max == 0) { + return; + } + + if (cbk->amount == cbk->max) { + //find least deep + real_t min_depth = 1e20; + int min_depth_idx = 0; + for (int i = 0; i < cbk->amount; i++) { + real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]); + if (d < min_depth) { + min_depth = d; + min_depth_idx = i; + } + } + + real_t d = p_point_A.distance_squared_to(p_point_B); + if (d < min_depth) { + return; + } + cbk->ptr[min_depth_idx * 2 + 0] = p_point_A; + cbk->ptr[min_depth_idx * 2 + 1] = p_point_B; + + } else { + cbk->ptr[cbk->amount * 2 + 0] = p_point_A; + cbk->ptr[cbk->amount * 2 + 1] = p_point_B; + cbk->amount++; + } +} + +GodotPhysicsServer3D *GodotPhysicsServer3D::godot_singleton = nullptr; +GodotPhysicsServer3D::GodotPhysicsServer3D(bool p_using_threads) { + godot_singleton = this; + GodotBroadPhase3D::create_func = GodotBroadPhase3DBVH::_create; + + using_threads = p_using_threads; +}; diff --git a/servers/physics_3d/physics_server_3d_sw.h b/servers/physics_3d/godot_physics_server_3d.h index f283f83112..f5c8e0f60d 100644 --- a/servers/physics_3d/physics_server_3d_sw.h +++ b/servers/physics_3d/godot_physics_server_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* physics_server_3d_sw.h */ +/* godot_physics_server_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,47 +28,48 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PHYSICS_SERVER_SW -#define PHYSICS_SERVER_SW +#ifndef GODOT_PHYSICS_SERVER_3D_H +#define GODOT_PHYSICS_SERVER_3D_H + +#include "godot_joint_3d.h" +#include "godot_shape_3d.h" +#include "godot_space_3d.h" +#include "godot_step_3d.h" #include "core/templates/rid_owner.h" -#include "joints_3d_sw.h" #include "servers/physics_server_3d.h" -#include "shape_3d_sw.h" -#include "space_3d_sw.h" -#include "step_3d_sw.h" -class PhysicsServer3DSW : public PhysicsServer3D { - GDCLASS(PhysicsServer3DSW, PhysicsServer3D); +class GodotPhysicsServer3D : public PhysicsServer3D { + GDCLASS(GodotPhysicsServer3D, PhysicsServer3D); - friend class PhysicsDirectSpaceState3DSW; - bool active; - int iterations; + friend class GodotPhysicsDirectSpaceState3D; + bool active = true; + int iterations = 0; - int island_count; - int active_objects; - int collision_pairs; + int island_count = 0; + int active_objects = 0; + int collision_pairs = 0; - bool using_threads; - bool doing_sync; - bool flushing_queries; + bool using_threads = false; + bool doing_sync = false; + bool flushing_queries = false; - Step3DSW *stepper; - Set<const Space3DSW *> active_spaces; + GodotStep3D *stepper = nullptr; + Set<const GodotSpace3D *> active_spaces; - mutable RID_PtrOwner<Shape3DSW, true> shape_owner; - mutable RID_PtrOwner<Space3DSW, true> space_owner; - mutable RID_PtrOwner<Area3DSW, true> area_owner; - mutable RID_PtrOwner<Body3DSW, true> body_owner; - mutable RID_PtrOwner<SoftBody3DSW, true> soft_body_owner; - mutable RID_PtrOwner<Joint3DSW, true> joint_owner; + mutable RID_PtrOwner<GodotShape3D, true> shape_owner; + mutable RID_PtrOwner<GodotSpace3D, true> space_owner; + mutable RID_PtrOwner<GodotArea3D, true> area_owner; + mutable RID_PtrOwner<GodotBody3D, true> body_owner; + mutable RID_PtrOwner<GodotSoftBody3D, true> soft_body_owner; + mutable RID_PtrOwner<GodotJoint3D, true> joint_owner; //void _clear_query(QuerySW *p_query); - friend class CollisionObject3DSW; - SelfList<CollisionObject3DSW>::List pending_shape_update_list; + friend class GodotCollisionObject3D; + SelfList<GodotCollisionObject3D>::List pending_shape_update_list; void _update_shapes(); - static PhysicsServer3DSW *singletonsw; + static GodotPhysicsServer3D *godot_singleton; public: struct CollCbkData { @@ -79,7 +80,7 @@ public: static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata); - virtual RID plane_shape_create() override; + virtual RID world_boundary_shape_create() override; virtual RID separation_ray_shape_create() override; virtual RID sphere_shape_create() override; virtual RID box_shape_create() override; @@ -121,9 +122,6 @@ public: virtual RID area_create() override; - virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) override; - virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const override; - virtual void area_set_space(RID p_area, RID p_space) override; virtual RID area_get_space(RID p_area) const override; @@ -156,8 +154,8 @@ public: virtual void area_set_monitorable(RID p_area, bool p_monitorable) override; - virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override; - virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) override; + virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) override; + virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) override; /* BODY API */ @@ -198,8 +196,10 @@ public: virtual void body_set_user_flags(RID p_body, uint32_t p_flags) override; virtual uint32_t body_get_user_flags(RID p_body) const override; - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) override; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const override; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) override; + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const override; + + virtual void body_reset_mass_properties(RID p_body) override; virtual void body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) override; virtual Variant body_get_state(RID p_body, BodyState p_state) const override; @@ -240,7 +240,7 @@ public: virtual void body_set_ray_pickable(RID p_body, bool p_enable) override; - virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override; + virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override; // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) override; @@ -289,7 +289,7 @@ public: virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) override; virtual real_t soft_body_get_drag_coefficient(RID p_body) const override; - virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) override; + virtual void soft_body_set_mesh(RID p_body, RID p_mesh) override; virtual AABB soft_body_get_bounds(RID p_body) const override; @@ -370,8 +370,8 @@ public: int get_process_info(ProcessInfo p_info) override; - PhysicsServer3DSW(bool p_using_threads = false); - ~PhysicsServer3DSW() {} + GodotPhysicsServer3D(bool p_using_threads = false); + ~GodotPhysicsServer3D() {} }; -#endif +#endif // GODOT_PHYSICS_SERVER_3D_H diff --git a/servers/physics_3d/shape_3d_sw.cpp b/servers/physics_3d/godot_shape_3d.cpp index b81d3272c3..5364a9833d 100644 --- a/servers/physics_3d/shape_3d_sw.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* shape_3d_sw.cpp */ +/* godot_shape_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,18 +28,18 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "shape_3d_sw.h" +#include "godot_shape_3d.h" #include "core/io/image.h" #include "core/math/convex_hull.h" #include "core/math/geometry_3d.h" #include "core/templates/sort_array.h" -// HeightMapShape3DSW is based on Bullet btHeightfieldTerrainShape. +// GodotHeightMapShape3D is based on Bullet btHeightfieldTerrainShape. /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2009 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -58,16 +58,16 @@ subject to the following restrictions: #define _CYLINDER_EDGE_IS_VALID_SUPPORT_THRESHOLD 0.002 #define _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD 0.999 -void Shape3DSW::configure(const AABB &p_aabb) { +void GodotShape3D::configure(const AABB &p_aabb) { aabb = p_aabb; configured = true; - for (Map<ShapeOwner3DSW *, int>::Element *E = owners.front(); E; E = E->next()) { - ShapeOwner3DSW *co = (ShapeOwner3DSW *)E->key(); + for (const KeyValue<GodotShapeOwner3D *, int> &E : owners) { + GodotShapeOwner3D *co = (GodotShapeOwner3D *)E.key; co->_shape_changed(); } } -Vector3 Shape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotShape3D::get_support(const Vector3 &p_normal) const { Vector3 res; int amnt; FeatureType type; @@ -75,8 +75,8 @@ Vector3 Shape3DSW::get_support(const Vector3 &p_normal) const { return res; } -void Shape3DSW::add_owner(ShapeOwner3DSW *p_owner) { - Map<ShapeOwner3DSW *, int>::Element *E = owners.find(p_owner); +void GodotShape3D::add_owner(GodotShapeOwner3D *p_owner) { + Map<GodotShapeOwner3D *, int>::Element *E = owners.find(p_owner); if (E) { E->get()++; } else { @@ -84,8 +84,8 @@ void Shape3DSW::add_owner(ShapeOwner3DSW *p_owner) { } } -void Shape3DSW::remove_owner(ShapeOwner3DSW *p_owner) { - Map<ShapeOwner3DSW *, int>::Element *E = owners.find(p_owner); +void GodotShape3D::remove_owner(GodotShapeOwner3D *p_owner) { + Map<GodotShapeOwner3D *, int>::Element *E = owners.find(p_owner); ERR_FAIL_COND(!E); E->get()--; if (E->get() == 0) { @@ -93,38 +93,33 @@ void Shape3DSW::remove_owner(ShapeOwner3DSW *p_owner) { } } -bool Shape3DSW::is_owner(ShapeOwner3DSW *p_owner) const { +bool GodotShape3D::is_owner(GodotShapeOwner3D *p_owner) const { return owners.has(p_owner); } -const Map<ShapeOwner3DSW *, int> &Shape3DSW::get_owners() const { +const Map<GodotShapeOwner3D *, int> &GodotShape3D::get_owners() const { return owners; } -Shape3DSW::Shape3DSW() { - custom_bias = 0; - configured = false; -} - -Shape3DSW::~Shape3DSW() { +GodotShape3D::~GodotShape3D() { ERR_FAIL_COND(owners.size()); } -Plane PlaneShape3DSW::get_plane() const { +Plane GodotWorldBoundaryShape3D::get_plane() const { return plane; } -void PlaneShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotWorldBoundaryShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { // gibberish, a plane is infinity r_min = -1e7; r_max = 1e7; } -Vector3 PlaneShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotWorldBoundaryShape3D::get_support(const Vector3 &p_normal) const { return p_normal * 1e15; } -bool PlaneShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotWorldBoundaryShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { bool inters = plane.intersects_segment(p_begin, p_end, &r_result); if (inters) { r_normal = plane.normal; @@ -132,11 +127,11 @@ bool PlaneShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_ return inters; } -bool PlaneShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotWorldBoundaryShape3D::intersect_point(const Vector3 &p_point) const { return plane.distance_to(p_point) < 0; } -Vector3 PlaneShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotWorldBoundaryShape3D::get_closest_point_to(const Vector3 &p_point) const { if (plane.is_point_over(p_point)) { return plane.project(p_point); } else { @@ -144,43 +139,43 @@ Vector3 PlaneShape3DSW::get_closest_point_to(const Vector3 &p_point) const { } } -Vector3 PlaneShape3DSW::get_moment_of_inertia(real_t p_mass) const { - return Vector3(); //wtf +Vector3 GodotWorldBoundaryShape3D::get_moment_of_inertia(real_t p_mass) const { + return Vector3(); // not applicable. } -void PlaneShape3DSW::_setup(const Plane &p_plane) { +void GodotWorldBoundaryShape3D::_setup(const Plane &p_plane) { plane = p_plane; configure(AABB(Vector3(-1e4, -1e4, -1e4), Vector3(1e4 * 2, 1e4 * 2, 1e4 * 2))); } -void PlaneShape3DSW::set_data(const Variant &p_data) { +void GodotWorldBoundaryShape3D::set_data(const Variant &p_data) { _setup(p_data); } -Variant PlaneShape3DSW::get_data() const { +Variant GodotWorldBoundaryShape3D::get_data() const { return plane; } -PlaneShape3DSW::PlaneShape3DSW() { +GodotWorldBoundaryShape3D::GodotWorldBoundaryShape3D() { } // -real_t SeparationRayShape3DSW::get_length() const { +real_t GodotSeparationRayShape3D::get_length() const { return length; } -bool SeparationRayShape3DSW::get_slide_on_slope() const { +bool GodotSeparationRayShape3D::get_slide_on_slope() const { return slide_on_slope; } -void SeparationRayShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotSeparationRayShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { // don't think this will be even used r_min = 0; r_max = 1; } -Vector3 SeparationRayShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotSeparationRayShape3D::get_support(const Vector3 &p_normal) const { if (p_normal.z > 0) { return Vector3(0, 0, length); } else { @@ -188,7 +183,7 @@ Vector3 SeparationRayShape3DSW::get_support(const Vector3 &p_normal) const { } } -void SeparationRayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { +void GodotSeparationRayShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { if (Math::abs(p_normal.z) < _EDGE_IS_VALID_SUPPORT_THRESHOLD) { r_amount = 2; r_type = FEATURE_EDGE; @@ -205,15 +200,15 @@ void SeparationRayShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve } } -bool SeparationRayShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotSeparationRayShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { return false; //simply not possible } -bool SeparationRayShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotSeparationRayShape3D::intersect_point(const Vector3 &p_point) const { return false; //simply not possible } -Vector3 SeparationRayShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotSeparationRayShape3D::get_closest_point_to(const Vector3 &p_point) const { Vector3 s[2] = { Vector3(0, 0, 0), Vector3(0, 0, length) @@ -222,40 +217,37 @@ Vector3 SeparationRayShape3DSW::get_closest_point_to(const Vector3 &p_point) con return Geometry3D::get_closest_point_to_segment(p_point, s); } -Vector3 SeparationRayShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotSeparationRayShape3D::get_moment_of_inertia(real_t p_mass) const { return Vector3(); } -void SeparationRayShape3DSW::_setup(real_t p_length, bool p_slide_on_slope) { +void GodotSeparationRayShape3D::_setup(real_t p_length, bool p_slide_on_slope) { length = p_length; slide_on_slope = p_slide_on_slope; configure(AABB(Vector3(0, 0, 0), Vector3(0.1, 0.1, length))); } -void SeparationRayShape3DSW::set_data(const Variant &p_data) { +void GodotSeparationRayShape3D::set_data(const Variant &p_data) { Dictionary d = p_data; _setup(d["length"], d["slide_on_slope"]); } -Variant SeparationRayShape3DSW::get_data() const { +Variant GodotSeparationRayShape3D::get_data() const { Dictionary d; d["length"] = length; d["slide_on_slope"] = slide_on_slope; return d; } -SeparationRayShape3DSW::SeparationRayShape3DSW() { - length = 1; - slide_on_slope = false; -} +GodotSeparationRayShape3D::GodotSeparationRayShape3D() {} /********** SPHERE *************/ -real_t SphereShape3DSW::get_radius() const { +real_t GodotSphereShape3D::get_radius() const { return radius; } -void SphereShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotSphereShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { real_t d = p_normal.dot(p_transform.origin); // figure out scale at point @@ -266,25 +258,25 @@ void SphereShape3DSW::project_range(const Vector3 &p_normal, const Transform3D & r_max = d + (radius)*scale; } -Vector3 SphereShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotSphereShape3D::get_support(const Vector3 &p_normal) const { return p_normal * radius; } -void SphereShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { +void GodotSphereShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { *r_supports = p_normal * radius; r_amount = 1; r_type = FEATURE_POINT; } -bool SphereShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotSphereShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { return Geometry3D::segment_intersects_sphere(p_begin, p_end, Vector3(), radius, &r_result, &r_normal); } -bool SphereShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotSphereShape3D::intersect_point(const Vector3 &p_point) const { return p_point.length() < radius; } -Vector3 SphereShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotSphereShape3D::get_closest_point_to(const Vector3 &p_point) const { Vector3 p = p_point; real_t l = p.length(); if (l < radius) { @@ -293,31 +285,29 @@ Vector3 SphereShape3DSW::get_closest_point_to(const Vector3 &p_point) const { return (p / l) * radius; } -Vector3 SphereShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotSphereShape3D::get_moment_of_inertia(real_t p_mass) const { real_t s = 0.4 * p_mass * radius * radius; return Vector3(s, s, s); } -void SphereShape3DSW::_setup(real_t p_radius) { +void GodotSphereShape3D::_setup(real_t p_radius) { radius = p_radius; configure(AABB(Vector3(-radius, -radius, -radius), Vector3(radius * 2.0, radius * 2.0, radius * 2.0))); } -void SphereShape3DSW::set_data(const Variant &p_data) { +void GodotSphereShape3D::set_data(const Variant &p_data) { _setup(p_data); } -Variant SphereShape3DSW::get_data() const { +Variant GodotSphereShape3D::get_data() const { return radius; } -SphereShape3DSW::SphereShape3DSW() { - radius = 0; -} +GodotSphereShape3D::GodotSphereShape3D() {} /********** BOX *************/ -void BoxShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotBoxShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { // no matter the angle, the box is mirrored anyway Vector3 local_normal = p_transform.basis.xform_inv(p_normal); @@ -328,7 +318,7 @@ void BoxShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_t r_max = distance + length; } -Vector3 BoxShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotBoxShape3D::get_support(const Vector3 &p_normal) const { Vector3 point( (p_normal.x < 0) ? -half_extents.x : half_extents.x, (p_normal.y < 0) ? -half_extents.y : half_extents.y, @@ -337,7 +327,7 @@ Vector3 BoxShape3DSW::get_support(const Vector3 &p_normal) const { return point; } -void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { +void GodotBoxShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { static const int next[3] = { 1, 2, 0 }; static const int next2[3] = { 2, 0, 1 }; @@ -420,17 +410,17 @@ void BoxShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_s r_supports[0] = point; } -bool BoxShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotBoxShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { AABB aabb(-half_extents, half_extents * 2.0); return aabb.intersects_segment(p_begin, p_end, &r_result, &r_normal); } -bool BoxShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotBoxShape3D::intersect_point(const Vector3 &p_point) const { return (Math::abs(p_point.x) < half_extents.x && Math::abs(p_point.y) < half_extents.y && Math::abs(p_point.z) < half_extents.z); } -Vector3 BoxShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotBoxShape3D::get_closest_point_to(const Vector3 &p_point) const { int outside = 0; Vector3 min_point; @@ -440,7 +430,7 @@ Vector3 BoxShape3DSW::get_closest_point_to(const Vector3 &p_point) const { if (outside == 1) { //use plane if only one side matches Vector3 n; - n[i] = SGN(p_point[i]); + n[i] = SIGN(p_point[i]); Plane p(n, half_extents[i]); min_point = p.project(p_point); @@ -480,7 +470,7 @@ Vector3 BoxShape3DSW::get_closest_point_to(const Vector3 &p_point) const { return min_point; } -Vector3 BoxShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotBoxShape3D::get_moment_of_inertia(real_t p_mass) const { real_t lx = half_extents.x; real_t ly = half_extents.y; real_t lz = half_extents.z; @@ -488,26 +478,25 @@ Vector3 BoxShape3DSW::get_moment_of_inertia(real_t p_mass) const { return Vector3((p_mass / 3.0) * (ly * ly + lz * lz), (p_mass / 3.0) * (lx * lx + lz * lz), (p_mass / 3.0) * (lx * lx + ly * ly)); } -void BoxShape3DSW::_setup(const Vector3 &p_half_extents) { +void GodotBoxShape3D::_setup(const Vector3 &p_half_extents) { half_extents = p_half_extents.abs(); configure(AABB(-half_extents, half_extents * 2)); } -void BoxShape3DSW::set_data(const Variant &p_data) { +void GodotBoxShape3D::set_data(const Variant &p_data) { _setup(p_data); } -Variant BoxShape3DSW::get_data() const { +Variant GodotBoxShape3D::get_data() const { return half_extents; } -BoxShape3DSW::BoxShape3DSW() { -} +GodotBoxShape3D::GodotBoxShape3D() {} /********** CAPSULE *************/ -void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotCapsuleShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { Vector3 n = p_transform.basis.xform_inv(p_normal).normalized(); real_t h = height * 0.5 - radius; @@ -518,7 +507,7 @@ void CapsuleShape3DSW::project_range(const Vector3 &p_normal, const Transform3D r_min = p_normal.dot(p_transform.xform(-n)); } -Vector3 CapsuleShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotCapsuleShape3D::get_support(const Vector3 &p_normal) const { Vector3 n = p_normal; real_t h = height * 0.5 - radius; @@ -528,7 +517,7 @@ Vector3 CapsuleShape3DSW::get_support(const Vector3 &p_normal) const { return n; } -void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { +void GodotCapsuleShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { Vector3 n = p_normal; real_t d = n.y; @@ -557,7 +546,7 @@ void CapsuleShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 } } -bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotCapsuleShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { Vector3 norm = (p_end - p_begin).normalized(); real_t min_d = 1e20; @@ -613,7 +602,7 @@ bool CapsuleShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 & return collision; } -bool CapsuleShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotCapsuleShape3D::intersect_point(const Vector3 &p_point) const { if (Math::abs(p_point.y) < height * 0.5 - radius) { return Vector3(p_point.x, 0, p_point.z).length() < radius; } else { @@ -623,7 +612,7 @@ bool CapsuleShape3DSW::intersect_point(const Vector3 &p_point) const { } } -Vector3 CapsuleShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotCapsuleShape3D::get_closest_point_to(const Vector3 &p_point) const { Vector3 s[2] = { Vector3(0, -height * 0.5 + radius, 0), Vector3(0, height * 0.5 - radius, 0), @@ -638,7 +627,7 @@ Vector3 CapsuleShape3DSW::get_closest_point_to(const Vector3 &p_point) const { return p + (p_point - p).normalized() * radius; } -Vector3 CapsuleShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotCapsuleShape3D::get_moment_of_inertia(real_t p_mass) const { // use bad AABB approximation Vector3 extents = get_aabb().size * 0.5; @@ -648,33 +637,31 @@ Vector3 CapsuleShape3DSW::get_moment_of_inertia(real_t p_mass) const { (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y)); } -void CapsuleShape3DSW::_setup(real_t p_height, real_t p_radius) { +void GodotCapsuleShape3D::_setup(real_t p_height, real_t p_radius) { height = p_height; radius = p_radius; configure(AABB(Vector3(-radius, -height * 0.5, -radius), Vector3(radius * 2, height, radius * 2))); } -void CapsuleShape3DSW::set_data(const Variant &p_data) { +void GodotCapsuleShape3D::set_data(const Variant &p_data) { Dictionary d = p_data; ERR_FAIL_COND(!d.has("radius")); ERR_FAIL_COND(!d.has("height")); _setup(d["height"], d["radius"]); } -Variant CapsuleShape3DSW::get_data() const { +Variant GodotCapsuleShape3D::get_data() const { Dictionary d; d["radius"] = radius; d["height"] = height; return d; } -CapsuleShape3DSW::CapsuleShape3DSW() { - height = radius = 0; -} +GodotCapsuleShape3D::GodotCapsuleShape3D() {} /********** CYLINDER *************/ -void CylinderShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotCylinderShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { Vector3 cylinder_axis = p_transform.basis.get_axis(1).normalized(); real_t axis_dot = cylinder_axis.dot(p_normal); @@ -696,7 +683,7 @@ void CylinderShape3DSW::project_range(const Vector3 &p_normal, const Transform3D r_max = distance + length; } -Vector3 CylinderShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotCylinderShape3D::get_support(const Vector3 &p_normal) const { Vector3 n = p_normal; real_t h = (n.y > 0) ? height : -height; real_t s = Math::sqrt(n.x * n.x + n.z * n.z); @@ -714,7 +701,7 @@ Vector3 CylinderShape3DSW::get_support(const Vector3 &p_normal) const { return n; } -void CylinderShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { +void GodotCylinderShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { real_t d = p_normal.y; if (Math::abs(d) > _CYLINDER_FACE_IS_VALID_SUPPORT_THRESHOLD) { real_t h = (d > 0) ? height : -height; @@ -774,23 +761,23 @@ void CylinderShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 } } -bool CylinderShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotCylinderShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { return Geometry3D::segment_intersects_cylinder(p_begin, p_end, height, radius, &r_result, &r_normal, 1); } -bool CylinderShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotCylinderShape3D::intersect_point(const Vector3 &p_point) const { if (Math::abs(p_point.y) < height * 0.5) { return Vector3(p_point.x, 0, p_point.z).length() < radius; } return false; } -Vector3 CylinderShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotCylinderShape3D::get_closest_point_to(const Vector3 &p_point) const { if (Math::absf(p_point.y) > height * 0.5) { // Project point to top disk. real_t dir = p_point.y > 0.0 ? 1.0 : -1.0; Vector3 circle_pos(0.0, dir * height * 0.5, 0.0); - Plane circle_plane(circle_pos, Vector3(0.0, dir, 0.0)); + Plane circle_plane(Vector3(0.0, dir, 0.0), circle_pos); Vector3 proj_point = circle_plane.project(p_point); // Clip position. @@ -818,7 +805,7 @@ Vector3 CylinderShape3DSW::get_closest_point_to(const Vector3 &p_point) const { } } -Vector3 CylinderShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotCylinderShape3D::get_moment_of_inertia(real_t p_mass) const { // use bad AABB approximation Vector3 extents = get_aabb().size * 0.5; @@ -828,33 +815,31 @@ Vector3 CylinderShape3DSW::get_moment_of_inertia(real_t p_mass) const { (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y)); } -void CylinderShape3DSW::_setup(real_t p_height, real_t p_radius) { +void GodotCylinderShape3D::_setup(real_t p_height, real_t p_radius) { height = p_height; radius = p_radius; configure(AABB(Vector3(-radius, -height * 0.5, -radius), Vector3(radius * 2.0, height, radius * 2.0))); } -void CylinderShape3DSW::set_data(const Variant &p_data) { +void GodotCylinderShape3D::set_data(const Variant &p_data) { Dictionary d = p_data; ERR_FAIL_COND(!d.has("radius")); ERR_FAIL_COND(!d.has("height")); _setup(d["height"], d["radius"]); } -Variant CylinderShape3DSW::get_data() const { +Variant GodotCylinderShape3D::get_data() const { Dictionary d; d["radius"] = radius; d["height"] = height; return d; } -CylinderShape3DSW::CylinderShape3DSW() { - height = radius = 0; -} +GodotCylinderShape3D::GodotCylinderShape3D() {} /********** CONVEX POLYGON *************/ -void ConvexPolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotConvexPolygonShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { int vertex_count = mesh.vertices.size(); if (vertex_count == 0) { return; @@ -874,7 +859,7 @@ void ConvexPolygonShape3DSW::project_range(const Vector3 &p_normal, const Transf } } -Vector3 ConvexPolygonShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotConvexPolygonShape3D::get_support(const Vector3 &p_normal) const { Vector3 n = p_normal; int vert_support_idx = -1; @@ -899,7 +884,7 @@ Vector3 ConvexPolygonShape3DSW::get_support(const Vector3 &p_normal) const { return vrts[vert_support_idx]; } -void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { +void GodotConvexPolygonShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { const Geometry3D::MeshData::Face *faces = mesh.faces.ptr(); int fc = mesh.faces.size(); @@ -969,7 +954,7 @@ void ConvexPolygonShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Ve r_type = FEATURE_POINT; } -bool ConvexPolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotConvexPolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { const Geometry3D::MeshData::Face *faces = mesh.faces.ptr(); int fc = mesh.faces.size(); @@ -1007,7 +992,7 @@ bool ConvexPolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Vec return col; } -bool ConvexPolygonShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotConvexPolygonShape3D::intersect_point(const Vector3 &p_point) const { const Geometry3D::MeshData::Face *faces = mesh.faces.ptr(); int fc = mesh.faces.size(); @@ -1020,7 +1005,7 @@ bool ConvexPolygonShape3DSW::intersect_point(const Vector3 &p_point) const { return true; } -Vector3 ConvexPolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotConvexPolygonShape3D::get_closest_point_to(const Vector3 &p_point) const { const Geometry3D::MeshData::Face *faces = mesh.faces.ptr(); int fc = mesh.faces.size(); const Vector3 *vertices = mesh.vertices.ptr(); @@ -1040,7 +1025,7 @@ Vector3 ConvexPolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) con Vector3 a = vertices[indices[j]]; Vector3 b = vertices[indices[(j + 1) % ic]]; Vector3 n = (a - b).cross(faces[i].plane.normal).normalized(); - if (Plane(a, n).is_point_over(p_point)) { + if (Plane(n, a).is_point_over(p_point)) { is_inside = false; break; } @@ -1078,7 +1063,7 @@ Vector3 ConvexPolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) con return min_point; } -Vector3 ConvexPolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotConvexPolygonShape3D::get_moment_of_inertia(real_t p_mass) const { // use bad AABB approximation Vector3 extents = get_aabb().size * 0.5; @@ -1088,7 +1073,7 @@ Vector3 ConvexPolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const { (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y)); } -void ConvexPolygonShape3DSW::_setup(const Vector<Vector3> &p_vertices) { +void GodotConvexPolygonShape3D::_setup(const Vector<Vector3> &p_vertices) { Error err = ConvexHullComputer::convex_hull(p_vertices, mesh); if (err != OK) { ERR_PRINT("Failed to build convex hull"); @@ -1107,20 +1092,20 @@ void ConvexPolygonShape3DSW::_setup(const Vector<Vector3> &p_vertices) { configure(_aabb); } -void ConvexPolygonShape3DSW::set_data(const Variant &p_data) { +void GodotConvexPolygonShape3D::set_data(const Variant &p_data) { _setup(p_data); } -Variant ConvexPolygonShape3DSW::get_data() const { +Variant GodotConvexPolygonShape3D::get_data() const { return mesh.vertices; } -ConvexPolygonShape3DSW::ConvexPolygonShape3DSW() { +GodotConvexPolygonShape3D::GodotConvexPolygonShape3D() { } /********** FACE POLYGON *************/ -void FaceShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotFaceShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { for (int i = 0; i < 3; i++) { Vector3 v = p_transform.xform(vertex[i]); real_t d = p_normal.dot(v); @@ -1135,7 +1120,7 @@ void FaceShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_ } } -Vector3 FaceShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotFaceShape3D::get_support(const Vector3 &p_normal) const { int vert_support_idx = -1; real_t support_max = 0; @@ -1151,7 +1136,7 @@ Vector3 FaceShape3DSW::get_support(const Vector3 &p_normal) const { return vertex[vert_support_idx]; } -void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { +void GodotFaceShape3D::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { Vector3 n = p_normal; /** TEST FACE AS SUPPORT **/ @@ -1203,12 +1188,12 @@ void FaceShape3DSW::get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_ r_supports[0] = vertex[vert_support_idx]; } -bool FaceShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotFaceShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { bool c = Geometry3D::segment_intersects_triangle(p_begin, p_end, vertex[0], vertex[1], vertex[2], &r_result); if (c) { r_normal = Plane(vertex[0], vertex[1], vertex[2]).normal; if (r_normal.dot(p_end - p_begin) > 0) { - if (backface_collision) { + if (backface_collision && p_hit_back_faces) { r_normal = -r_normal; } else { c = false; @@ -1219,23 +1204,23 @@ bool FaceShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_e return c; } -bool FaceShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotFaceShape3D::intersect_point(const Vector3 &p_point) const { return false; //face is flat } -Vector3 FaceShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotFaceShape3D::get_closest_point_to(const Vector3 &p_point) const { return Face3(vertex[0], vertex[1], vertex[2]).get_closest_point_to(p_point); } -Vector3 FaceShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotFaceShape3D::get_moment_of_inertia(real_t p_mass) const { return Vector3(); // Sorry, but i don't think anyone cares, FaceShape! } -FaceShape3DSW::FaceShape3DSW() { +GodotFaceShape3D::GodotFaceShape3D() { configure(AABB()); } -Vector<Vector3> ConcavePolygonShape3DSW::get_faces() const { +Vector<Vector3> GodotConcavePolygonShape3D::get_faces() const { Vector<Vector3> rfaces; rfaces.resize(faces.size() * 3); @@ -1250,7 +1235,7 @@ Vector<Vector3> ConcavePolygonShape3DSW::get_faces() const { return rfaces; } -void ConcavePolygonShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotConcavePolygonShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { int count = vertices.size(); if (count == 0) { r_min = 0; @@ -1271,7 +1256,7 @@ void ConcavePolygonShape3DSW::project_range(const Vector3 &p_normal, const Trans } } -Vector3 ConcavePolygonShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotConcavePolygonShape3D::get_support(const Vector3 &p_normal) const { int count = vertices.size(); if (count == 0) { return Vector3(); @@ -1296,7 +1281,7 @@ Vector3 ConcavePolygonShape3DSW::get_support(const Vector3 &p_normal) const { return vptr[vert_support_idx]; } -void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_params) const { +void GodotConcavePolygonShape3D::_cull_segment(int p_idx, _SegmentCullParams *p_params) const { const BVH *bvh = &p_params->bvh[p_idx]; /* @@ -1311,7 +1296,7 @@ void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_par if (bvh->face_index >= 0) { const Face *f = &p_params->faces[bvh->face_index]; - FaceShape3DSW *face = p_params->face; + GodotFaceShape3D *face = p_params->face; face->normal = f->normal; face->vertex[0] = p_params->vertices[f->indices[0]]; face->vertex[1] = p_params->vertices[f->indices[1]]; @@ -1319,7 +1304,7 @@ void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_par Vector3 res; Vector3 normal; - if (face->intersect_segment(p_params->from, p_params->to, res, normal)) { + if (face->intersect_segment(p_params->from, p_params->to, res, normal, true)) { real_t d = p_params->dir.dot(res) - p_params->dir.dot(p_params->from); if ((d > 0) && (d < p_params->min_d)) { p_params->min_d = d; @@ -1338,7 +1323,7 @@ void ConcavePolygonShape3DSW::_cull_segment(int p_idx, _SegmentCullParams *p_par } } -bool ConcavePolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotConcavePolygonShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { if (faces.size() == 0) { return false; } @@ -1348,8 +1333,8 @@ bool ConcavePolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Ve const Vector3 *vr = vertices.ptr(); const BVH *br = bvh.ptr(); - FaceShape3DSW face; - face.backface_collision = backface_collision; + GodotFaceShape3D face; + face.backface_collision = backface_collision && p_hit_back_faces; _SegmentCullParams params; params.from = p_begin; @@ -1374,15 +1359,15 @@ bool ConcavePolygonShape3DSW::intersect_segment(const Vector3 &p_begin, const Ve } } -bool ConcavePolygonShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotConcavePolygonShape3D::intersect_point(const Vector3 &p_point) const { return false; //face is flat } -Vector3 ConcavePolygonShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotConcavePolygonShape3D::get_closest_point_to(const Vector3 &p_point) const { return Vector3(); } -bool ConcavePolygonShape3DSW::_cull(int p_idx, _CullParams *p_params) const { +bool GodotConcavePolygonShape3D::_cull(int p_idx, _CullParams *p_params) const { const BVH *bvh = &p_params->bvh[p_idx]; if (!p_params->aabb.intersects(bvh->aabb)) { @@ -1391,7 +1376,7 @@ bool ConcavePolygonShape3DSW::_cull(int p_idx, _CullParams *p_params) const { if (bvh->face_index >= 0) { const Face *f = &p_params->faces[bvh->face_index]; - FaceShape3DSW *face = p_params->face; + GodotFaceShape3D *face = p_params->face; face->normal = f->normal; face->vertex[0] = p_params->vertices[f->indices[0]]; face->vertex[1] = p_params->vertices[f->indices[1]]; @@ -1416,7 +1401,7 @@ bool ConcavePolygonShape3DSW::_cull(int p_idx, _CullParams *p_params) const { return false; } -void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const { +void GodotConcavePolygonShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const { // make matrix local to concave if (faces.size() == 0) { return; @@ -1429,8 +1414,9 @@ void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_cal const Vector3 *vr = vertices.ptr(); const BVH *br = bvh.ptr(); - FaceShape3DSW face; // use this to send in the callback + GodotFaceShape3D face; // use this to send in the callback face.backface_collision = backface_collision; + face.invert_backface_collision = p_invert_backface_collision; _CullParams params; params.aabb = local_aabb; @@ -1445,7 +1431,7 @@ void ConcavePolygonShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_cal _cull(0, ¶ms); } -Vector3 ConcavePolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotConcavePolygonShape3D::get_moment_of_inertia(real_t p_mass) const { // use bad AABB approximation Vector3 extents = get_aabb().size * 0.5; @@ -1455,40 +1441,40 @@ Vector3 ConcavePolygonShape3DSW::get_moment_of_inertia(real_t p_mass) const { (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y)); } -struct _VolumeSW_BVH_Element { +struct _Volume_BVH_Element { AABB aabb; Vector3 center; int face_index; }; -struct _VolumeSW_BVH_CompareX { - _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const { +struct _Volume_BVH_CompareX { + _FORCE_INLINE_ bool operator()(const _Volume_BVH_Element &a, const _Volume_BVH_Element &b) const { return a.center.x < b.center.x; } }; -struct _VolumeSW_BVH_CompareY { - _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const { +struct _Volume_BVH_CompareY { + _FORCE_INLINE_ bool operator()(const _Volume_BVH_Element &a, const _Volume_BVH_Element &b) const { return a.center.y < b.center.y; } }; -struct _VolumeSW_BVH_CompareZ { - _FORCE_INLINE_ bool operator()(const _VolumeSW_BVH_Element &a, const _VolumeSW_BVH_Element &b) const { +struct _Volume_BVH_CompareZ { + _FORCE_INLINE_ bool operator()(const _Volume_BVH_Element &a, const _Volume_BVH_Element &b) const { return a.center.z < b.center.z; } }; -struct _VolumeSW_BVH { +struct _Volume_BVH { AABB aabb; - _VolumeSW_BVH *left; - _VolumeSW_BVH *right; + _Volume_BVH *left; + _Volume_BVH *right; int face_index; }; -_VolumeSW_BVH *_volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements, int p_size, int &count) { - _VolumeSW_BVH *bvh = memnew(_VolumeSW_BVH); +_Volume_BVH *_volume_build_bvh(_Volume_BVH_Element *p_elements, int p_size, int &count) { + _Volume_BVH *bvh = memnew(_Volume_BVH); if (p_size == 1) { //leaf @@ -1513,30 +1499,30 @@ _VolumeSW_BVH *_volume_sw_build_bvh(_VolumeSW_BVH_Element *p_elements, int p_siz bvh->aabb = aabb; switch (aabb.get_longest_axis_index()) { case 0: { - SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareX> sort_x; + SortArray<_Volume_BVH_Element, _Volume_BVH_CompareX> sort_x; sort_x.sort(p_elements, p_size); } break; case 1: { - SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareY> sort_y; + SortArray<_Volume_BVH_Element, _Volume_BVH_CompareY> sort_y; sort_y.sort(p_elements, p_size); } break; case 2: { - SortArray<_VolumeSW_BVH_Element, _VolumeSW_BVH_CompareZ> sort_z; + SortArray<_Volume_BVH_Element, _Volume_BVH_CompareZ> sort_z; sort_z.sort(p_elements, p_size); } break; } int split = p_size / 2; - bvh->left = _volume_sw_build_bvh(p_elements, split, count); - bvh->right = _volume_sw_build_bvh(&p_elements[split], p_size - split, count); + bvh->left = _volume_build_bvh(p_elements, split, count); + bvh->right = _volume_build_bvh(&p_elements[split], p_size - split, count); //printf("branch at %p - %i: %i\n",bvh,count,bvh->face_index); count++; return bvh; } -void ConcavePolygonShape3DSW::_fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx) { +void GodotConcavePolygonShape3D::_fill_bvh(_Volume_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx) { int idx = p_idx; p_bvh_array[idx].aabb = p_bvh_tree->aabb; @@ -1562,7 +1548,7 @@ void ConcavePolygonShape3DSW::_fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_ar memdelete(p_bvh_tree); } -void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_backface_collision) { +void GodotConcavePolygonShape3D::_setup(const Vector<Vector3> &p_faces, bool p_backface_collision) { int src_face_count = p_faces.size(); if (src_face_count == 0) { configure(AABB()); @@ -1573,10 +1559,10 @@ void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_back const Vector3 *facesr = p_faces.ptr(); - Vector<_VolumeSW_BVH_Element> bvh_array; + Vector<_Volume_BVH_Element> bvh_array; bvh_array.resize(src_face_count); - _VolumeSW_BVH_Element *bvh_arrayw = bvh_array.ptrw(); + _Volume_BVH_Element *bvh_arrayw = bvh_array.ptrw(); faces.resize(src_face_count); Face *facesw = faces.ptrw(); @@ -1591,7 +1577,7 @@ void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_back Face3 face(facesr[i * 3 + 0], facesr[i * 3 + 1], facesr[i * 3 + 2]); bvh_arrayw[i].aabb = face.get_aabb(); - bvh_arrayw[i].center = bvh_arrayw[i].aabb.position + bvh_arrayw[i].aabb.size * 0.5; + bvh_arrayw[i].center = bvh_arrayw[i].aabb.get_center(); bvh_arrayw[i].face_index = i; facesw[i].indices[0] = i * 3 + 0; facesw[i].indices[1] = i * 3 + 1; @@ -1608,7 +1594,7 @@ void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_back } int count = 0; - _VolumeSW_BVH *bvh_tree = _volume_sw_build_bvh(bvh_arrayw, src_face_count, count); + _Volume_BVH *bvh_tree = _volume_build_bvh(bvh_arrayw, src_face_count, count); bvh.resize(count + 1); @@ -1622,14 +1608,14 @@ void ConcavePolygonShape3DSW::_setup(const Vector<Vector3> &p_faces, bool p_back configure(_aabb); // this type of shape has no margin } -void ConcavePolygonShape3DSW::set_data(const Variant &p_data) { +void GodotConcavePolygonShape3D::set_data(const Variant &p_data) { Dictionary d = p_data; ERR_FAIL_COND(!d.has("faces")); _setup(d["faces"], d["backface_collision"]); } -Variant ConcavePolygonShape3DSW::get_data() const { +Variant GodotConcavePolygonShape3D::get_data() const { Dictionary d; d["faces"] = get_faces(); d["backface_collision"] = backface_collision; @@ -1637,29 +1623,29 @@ Variant ConcavePolygonShape3DSW::get_data() const { return d; } -ConcavePolygonShape3DSW::ConcavePolygonShape3DSW() { +GodotConcavePolygonShape3D::GodotConcavePolygonShape3D() { } /* HEIGHT MAP SHAPE */ -Vector<real_t> HeightMapShape3DSW::get_heights() const { +Vector<real_t> GodotHeightMapShape3D::get_heights() const { return heights; } -int HeightMapShape3DSW::get_width() const { +int GodotHeightMapShape3D::get_width() const { return width; } -int HeightMapShape3DSW::get_depth() const { +int GodotHeightMapShape3D::get_depth() const { return depth; } -void HeightMapShape3DSW::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { +void GodotHeightMapShape3D::project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { //not very useful, but not very used either - p_transform.xform(get_aabb()).project_range_in_plane(Plane(p_normal, 0), r_min, r_max); + p_transform.xform(get_aabb()).project_range_in_plane(Plane(p_normal), r_min, r_max); } -Vector3 HeightMapShape3DSW::get_support(const Vector3 &p_normal) const { +Vector3 GodotHeightMapShape3D::get_support(const Vector3 &p_normal) const { //not very useful, but not very used either return get_aabb().get_support(p_normal); } @@ -1672,14 +1658,25 @@ struct _HeightmapSegmentCullParams { Vector3 result; Vector3 normal; - const HeightMapShape3DSW *heightmap = nullptr; - FaceShape3DSW *face = nullptr; + const GodotHeightMapShape3D *heightmap = nullptr; + GodotFaceShape3D *face = nullptr; +}; + +struct _HeightmapGridCullState { + real_t length = 0.0; + real_t length_flat = 0.0; + + real_t dist = 0.0; + real_t prev_dist = 0.0; + + int x = 0; + int z = 0; }; _FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_params) { Vector3 res; Vector3 normal; - if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal)) { + if (p_params.face->intersect_segment(p_params.from, p_params.to, res, normal, true)) { p_params.result = res; p_params.normal = normal; return true; @@ -1688,11 +1685,11 @@ _FORCE_INLINE_ bool _heightmap_face_cull_segment(_HeightmapSegmentCullParams &p_ return false; } -_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, int p_x, int p_z) { +_FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_params, const _HeightmapGridCullState &p_state) { // First triangle. - p_params.heightmap->_get_point(p_x, p_z, p_params.face->vertex[0]); - p_params.heightmap->_get_point(p_x + 1, p_z, p_params.face->vertex[1]); - p_params.heightmap->_get_point(p_x, p_z + 1, p_params.face->vertex[2]); + p_params.heightmap->_get_point(p_state.x, p_state.z, p_params.face->vertex[0]); + p_params.heightmap->_get_point(p_state.x + 1, p_state.z, p_params.face->vertex[1]); + p_params.heightmap->_get_point(p_state.x, p_state.z + 1, p_params.face->vertex[2]); p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal; if (_heightmap_face_cull_segment(p_params)) { return true; @@ -1700,7 +1697,7 @@ _FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_ // Second triangle. p_params.face->vertex[0] = p_params.face->vertex[1]; - p_params.heightmap->_get_point(p_x + 1, p_z + 1, p_params.face->vertex[1]); + p_params.heightmap->_get_point(p_state.x + 1, p_state.z + 1, p_params.face->vertex[1]); p_params.face->normal = Plane(p_params.face->vertex[0], p_params.face->vertex[1], p_params.face->vertex[2]).normal; if (_heightmap_face_cull_segment(p_params)) { return true; @@ -1709,165 +1706,248 @@ _FORCE_INLINE_ bool _heightmap_cell_cull_segment(_HeightmapSegmentCullParams &p_ return false; } -bool HeightMapShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const { - if (heights.is_empty()) { +_FORCE_INLINE_ bool _heightmap_chunk_cull_segment(_HeightmapSegmentCullParams &p_params, const _HeightmapGridCullState &p_state) { + const GodotHeightMapShape3D::Range &chunk = p_params.heightmap->_get_bounds_chunk(p_state.x, p_state.z); + + Vector3 enter_pos; + Vector3 exit_pos; + + if (p_state.length_flat > CMP_EPSILON) { + real_t flat_to_3d = p_state.length / p_state.length_flat; + real_t enter_param = p_state.prev_dist * flat_to_3d; + real_t exit_param = p_state.dist * flat_to_3d; + enter_pos = p_params.from + p_params.dir * enter_param; + exit_pos = p_params.from + p_params.dir * exit_param; + } else { + // Consider the ray vertical. + // (though we shouldn't reach this often because there is an early check up-front) + enter_pos = p_params.from; + exit_pos = p_params.to; + } + + // Transform positions to heightmap space. + enter_pos *= GodotHeightMapShape3D::BOUNDS_CHUNK_SIZE; + exit_pos *= GodotHeightMapShape3D::BOUNDS_CHUNK_SIZE; + + // We did enter the flat projection of the AABB, + // but we have to check if we intersect it on the vertical axis. + if ((enter_pos.y > chunk.max) && (exit_pos.y > chunk.max)) { + return false; + } + if ((enter_pos.y < chunk.min) && (exit_pos.y < chunk.min)) { return false; } - Vector3 local_begin = p_begin + local_origin; - Vector3 local_end = p_end + local_origin; + return p_params.heightmap->_intersect_grid_segment(_heightmap_cell_cull_segment, enter_pos, exit_pos, p_params.heightmap->width, p_params.heightmap->depth, p_params.heightmap->local_origin, p_params.result, p_params.normal); +} - FaceShape3DSW face; +template <typename ProcessFunction> +bool GodotHeightMapShape3D::_intersect_grid_segment(ProcessFunction &p_process, const Vector3 &p_begin, const Vector3 &p_end, int p_width, int p_depth, const Vector3 &offset, Vector3 &r_point, Vector3 &r_normal) const { + Vector3 delta = (p_end - p_begin); + real_t length = delta.length(); + + if (length < CMP_EPSILON) { + return false; + } + + Vector3 local_begin = p_begin + offset; + + GodotFaceShape3D face; face.backface_collision = false; _HeightmapSegmentCullParams params; params.from = p_begin; params.to = p_end; - params.dir = (p_end - p_begin).normalized(); + params.dir = delta / length; params.heightmap = this; params.face = &face; - // Quantize the ray begin/end. - int begin_x = floor(local_begin.x); - int begin_z = floor(local_begin.z); - int end_x = floor(local_end.x); - int end_z = floor(local_end.z); + _HeightmapGridCullState state; - if ((begin_x == end_x) && (begin_z == end_z)) { - // Simple case for rays that don't traverse the grid horizontally. - // Just perform a test on the given cell. - int x = CLAMP(begin_x, 0, width - 2); - int z = CLAMP(begin_z, 0, depth - 2); - if (_heightmap_cell_cull_segment(params, x, z)) { - r_point = params.result; - r_normal = params.normal; - return true; - } - } else { - // Perform grid query from projected ray. - Vector2 ray_dir_proj(local_end.x - local_begin.x, local_end.z - local_begin.z); - real_t ray_dist_proj = ray_dir_proj.length(); + // Perform grid query from projected ray. + Vector2 ray_dir_flat(delta.x, delta.z); + state.length = length; + state.length_flat = ray_dir_flat.length(); - if (ray_dist_proj < CMP_EPSILON) { - ray_dir_proj = Vector2(); - } else { - ray_dir_proj /= ray_dist_proj; - } + if (state.length_flat < CMP_EPSILON) { + ray_dir_flat = Vector2(); + } else { + ray_dir_flat /= state.length_flat; + } - const int x_step = (ray_dir_proj.x > CMP_EPSILON) ? 1 : ((ray_dir_proj.x < -CMP_EPSILON) ? -1 : 0); - const int z_step = (ray_dir_proj.y > CMP_EPSILON) ? 1 : ((ray_dir_proj.y < -CMP_EPSILON) ? -1 : 0); + const int x_step = (ray_dir_flat.x > CMP_EPSILON) ? 1 : ((ray_dir_flat.x < -CMP_EPSILON) ? -1 : 0); + const int z_step = (ray_dir_flat.y > CMP_EPSILON) ? 1 : ((ray_dir_flat.y < -CMP_EPSILON) ? -1 : 0); - const real_t infinite = 1e20; - const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_proj.x) : infinite; - const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_proj.y) : infinite; + const real_t infinite = 1e20; + const real_t delta_x = (x_step != 0) ? 1.f / Math::abs(ray_dir_flat.x) : infinite; + const real_t delta_z = (z_step != 0) ? 1.f / Math::abs(ray_dir_flat.y) : infinite; - real_t cross_x; // At which value of `param` we will cross a x-axis lane? - real_t cross_z; // At which value of `param` we will cross a z-axis lane? + real_t cross_x; // At which value of `param` we will cross a x-axis lane? + real_t cross_z; // At which value of `param` we will cross a z-axis lane? - // X initialization. - if (x_step != 0) { - if (x_step == 1) { - cross_x = (ceil(local_begin.x) - local_begin.x) * delta_x; - } else { - cross_x = (local_begin.x - floor(local_begin.x)) * delta_x; - } + // X initialization. + if (x_step != 0) { + if (x_step == 1) { + cross_x = (Math::ceil(local_begin.x) - local_begin.x) * delta_x; } else { - cross_x = infinite; // Will never cross on X. + cross_x = (local_begin.x - Math::floor(local_begin.x)) * delta_x; } + } else { + cross_x = infinite; // Will never cross on X. + } - // Z initialization. - if (z_step != 0) { - if (z_step == 1) { - cross_z = (ceil(local_begin.z) - local_begin.z) * delta_z; - } else { - cross_z = (local_begin.z - floor(local_begin.z)) * delta_z; - } + // Z initialization. + if (z_step != 0) { + if (z_step == 1) { + cross_z = (Math::ceil(local_begin.z) - local_begin.z) * delta_z; } else { - cross_z = infinite; // Will never cross on Z. + cross_z = (local_begin.z - Math::floor(local_begin.z)) * delta_z; } + } else { + cross_z = infinite; // Will never cross on Z. + } - int x = floor(local_begin.x); - int z = floor(local_begin.z); + int x = Math::floor(local_begin.x); + int z = Math::floor(local_begin.z); - // Workaround cases where the ray starts at an integer position. - if (Math::is_zero_approx(cross_x)) { - cross_x += delta_x; - // If going backwards, we should ignore the position we would get by the above flooring, - // because the ray is not heading in that direction. - if (x_step == -1) { - x -= 1; - } + // Workaround cases where the ray starts at an integer position. + if (Math::is_zero_approx(cross_x)) { + cross_x += delta_x; + // If going backwards, we should ignore the position we would get by the above flooring, + // because the ray is not heading in that direction. + if (x_step == -1) { + x -= 1; } + } - if (Math::is_zero_approx(cross_z)) { - cross_z += delta_z; - if (z_step == -1) { - z -= 1; - } + if (Math::is_zero_approx(cross_z)) { + cross_z += delta_z; + if (z_step == -1) { + z -= 1; } + } + + // Start inside the grid. + int x_start = MAX(MIN(x, p_width - 2), 0); + int z_start = MAX(MIN(z, p_depth - 2), 0); - // Start inside the grid. - int x_start = CLAMP(x, 0, width - 2); - int z_start = CLAMP(z, 0, depth - 2); + // Adjust initial cross values. + cross_x += delta_x * x_step * (x_start - x); + cross_z += delta_z * z_step * (z_start - z); - // Adjust initial cross values. - cross_x += delta_x * x_step * (x_start - x); - cross_z += delta_z * z_step * (z_start - z); + x = x_start; + z = z_start; - x = x_start; - z = z_start; + while (true) { + state.prev_dist = state.dist; + state.x = x; + state.z = z; - if (_heightmap_cell_cull_segment(params, x, z)) { + if (cross_x < cross_z) { + // X lane. + x += x_step; + // Assign before advancing the param, + // to be in sync with the initialization step. + state.dist = cross_x; + cross_x += delta_x; + } else { + // Z lane. + z += z_step; + state.dist = cross_z; + cross_z += delta_z; + } + + if (state.dist > state.length_flat) { + state.dist = state.length_flat; + if (p_process(params, state)) { + r_point = params.result; + r_normal = params.normal; + return true; + } + break; + } + + if (p_process(params, state)) { r_point = params.result; r_normal = params.normal; return true; } - real_t dist = 0.0; - while (true) { - if (cross_x < cross_z) { - // X lane. - x += x_step; - // Assign before advancing the param, - // to be in sync with the initialization step. - dist = cross_x; - cross_x += delta_x; - } else { - // Z lane. - z += z_step; - dist = cross_z; - cross_z += delta_z; - } + // Stop when outside the grid. + if ((x < 0) || (z < 0) || (x >= p_width - 1) || (z >= p_depth - 1)) { + break; + } + } - // Stop when outside the grid. - if ((x < 0) || (z < 0) || (x >= width - 1) || (z >= depth - 1)) { - break; - } + return false; +} - if (_heightmap_cell_cull_segment(params, x, z)) { - r_point = params.result; - r_normal = params.normal; - return true; - } +bool GodotHeightMapShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, bool p_hit_back_faces) const { + if (heights.is_empty()) { + return false; + } - if (dist > ray_dist_proj) { - break; - } + Vector3 local_begin = p_begin + local_origin; + Vector3 local_end = p_end + local_origin; + + // Quantize the ray begin/end. + int begin_x = Math::floor(local_begin.x); + int begin_z = Math::floor(local_begin.z); + int end_x = Math::floor(local_end.x); + int end_z = Math::floor(local_end.z); + + if ((begin_x == end_x) && (begin_z == end_z)) { + // Simple case for rays that don't traverse the grid horizontally. + // Just perform a test on the given cell. + GodotFaceShape3D face; + face.backface_collision = p_hit_back_faces; + + _HeightmapSegmentCullParams params; + params.from = p_begin; + params.to = p_end; + params.dir = (p_end - p_begin).normalized(); + + params.heightmap = this; + params.face = &face; + + _HeightmapGridCullState state; + state.x = MAX(MIN(begin_x, width - 2), 0); + state.z = MAX(MIN(begin_z, depth - 2), 0); + if (_heightmap_cell_cull_segment(params, state)) { + r_point = params.result; + r_normal = params.normal; + return true; + } + } else if (bounds_grid.is_empty()) { + // Process all cells intersecting the flat projection of the ray. + return _intersect_grid_segment(_heightmap_cell_cull_segment, p_begin, p_end, width, depth, local_origin, r_point, r_normal); + } else { + Vector3 ray_diff = (p_end - p_begin); + real_t length_flat_sqr = ray_diff.x * ray_diff.x + ray_diff.z * ray_diff.z; + if (length_flat_sqr < BOUNDS_CHUNK_SIZE * BOUNDS_CHUNK_SIZE) { + // Don't use chunks, the ray is too short in the plane. + return _intersect_grid_segment(_heightmap_cell_cull_segment, p_begin, p_end, width, depth, local_origin, r_point, r_normal); + } else { + // The ray is long, run raycast on a higher-level grid. + Vector3 bounds_from = p_begin / BOUNDS_CHUNK_SIZE; + Vector3 bounds_to = p_end / BOUNDS_CHUNK_SIZE; + Vector3 bounds_offset = local_origin / BOUNDS_CHUNK_SIZE; + return _intersect_grid_segment(_heightmap_chunk_cull_segment, bounds_from, bounds_to, bounds_grid_width, bounds_grid_depth, bounds_offset, r_point, r_normal); } } return false; } -bool HeightMapShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotHeightMapShape3D::intersect_point(const Vector3 &p_point) const { return false; } -Vector3 HeightMapShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotHeightMapShape3D::get_closest_point_to(const Vector3 &p_point) const { return Vector3(); } -void HeightMapShape3DSW::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const { +void GodotHeightMapShape3D::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const { const AABB &aabb = get_aabb(); Vector3 pos_local = aabb.position + local_origin; @@ -1882,7 +1962,7 @@ void HeightMapShape3DSW::_get_cell(const Vector3 &p_point, int &r_x, int &r_y, i r_z = (clamped_point.z < 0.0) ? (clamped_point.z - 0.5) : (clamped_point.z + 0.5); } -void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const { +void GodotHeightMapShape3D::cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const { if (heights.is_empty()) { return; } @@ -1908,8 +1988,9 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback int start_z = MAX(0, aabb_min[2]); int end_z = MIN(depth - 1, aabb_max[2]); - FaceShape3DSW face; - face.backface_collision = true; + GodotFaceShape3D face; + face.backface_collision = !p_invert_backface_collision; + face.invert_backface_collision = p_invert_backface_collision; for (int z = start_z; z < end_z; z++) { for (int x = start_x; x < end_x; x++) { @@ -1917,7 +1998,7 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback _get_point(x, z, face.vertex[0]); _get_point(x + 1, z, face.vertex[1]); _get_point(x, z + 1, face.vertex[2]); - face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal; + face.normal = Plane(face.vertex[0], face.vertex[1], face.vertex[2]).normal; if (p_callback(p_userdata, &face)) { return; } @@ -1925,7 +2006,7 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback // Second triangle. face.vertex[0] = face.vertex[1]; _get_point(x + 1, z + 1, face.vertex[1]); - face.normal = Plane(face.vertex[0], face.vertex[2], face.vertex[1]).normal; + face.normal = Plane(face.vertex[0], face.vertex[1], face.vertex[2]).normal; if (p_callback(p_userdata, &face)) { return; } @@ -1933,7 +2014,7 @@ void HeightMapShape3DSW::cull(const AABB &p_local_aabb, QueryCallback p_callback } } -Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const { +Vector3 GodotHeightMapShape3D::get_moment_of_inertia(real_t p_mass) const { // use bad AABB approximation Vector3 extents = get_aabb().size * 0.5; @@ -1943,7 +2024,76 @@ Vector3 HeightMapShape3DSW::get_moment_of_inertia(real_t p_mass) const { (p_mass / 3.0) * (extents.x * extents.x + extents.y * extents.y)); } -void HeightMapShape3DSW::_setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { +void GodotHeightMapShape3D::_build_accelerator() { + bounds_grid.clear(); + + bounds_grid_width = width / BOUNDS_CHUNK_SIZE; + bounds_grid_depth = depth / BOUNDS_CHUNK_SIZE; + + if (width % BOUNDS_CHUNK_SIZE > 0) { + ++bounds_grid_width; // In case terrain size isn't dividable by chunk size. + } + + if (depth % BOUNDS_CHUNK_SIZE > 0) { + ++bounds_grid_depth; + } + + uint32_t bound_grid_size = (uint32_t)(bounds_grid_width * bounds_grid_depth); + + if (bound_grid_size < 2) { + // Grid is empty or just one chunk. + return; + } + + bounds_grid.resize(bound_grid_size); + + // Compute min and max height for all chunks. + for (int cz = 0; cz < bounds_grid_depth; ++cz) { + int z0 = cz * BOUNDS_CHUNK_SIZE; + + for (int cx = 0; cx < bounds_grid_width; ++cx) { + int x0 = cx * BOUNDS_CHUNK_SIZE; + + Range r; + + r.min = _get_height(x0, z0); + r.max = r.min; + + // Compute min and max height for this chunk. + // We have to include one extra cell to account for neighbors. + // Here is why: + // Say we have a flat terrain, and a plateau that fits a chunk perfectly. + // + // Left Right + // 0---0---0---1---1---1 + // | | | | | | + // 0---0---0---1---1---1 + // | | | | | | + // 0---0---0---1---1---1 + // x + // + // If the AABB for the Left chunk did not share vertices with the Right, + // then we would fail collision tests at x due to a gap. + // + int z_max = MIN(z0 + BOUNDS_CHUNK_SIZE + 1, depth); + int x_max = MIN(x0 + BOUNDS_CHUNK_SIZE + 1, width); + for (int z = z0; z < z_max; ++z) { + for (int x = x0; x < x_max; ++x) { + real_t height = _get_height(x, z); + if (height < r.min) { + r.min = height; + } else if (height > r.max) { + r.max = height; + } + } + } + + bounds_grid[cx + cz * bounds_grid_width] = r; + } + } +} + +void GodotHeightMapShape3D::_setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height) { heights = p_heights; width = p_width; depth = p_depth; @@ -1959,10 +2109,12 @@ void HeightMapShape3DSW::_setup(const Vector<real_t> &p_heights, int p_width, in aabb.position -= local_origin; + _build_accelerator(); + configure(aabb); } -void HeightMapShape3DSW::set_data(const Variant &p_data) { +void GodotHeightMapShape3D::set_data(const Variant &p_data) { ERR_FAIL_COND(p_data.get_type() != Variant::DICTIONARY); Dictionary d = p_data; @@ -2017,7 +2169,7 @@ void HeightMapShape3DSW::set_data(const Variant &p_data) { } else { int heights_size = heights.size(); for (int i = 0; i < heights_size; ++i) { - float h = heights[i]; + real_t h = heights[i]; if (h < min_height) { min_height = h; } else if (h > max_height) { @@ -2034,7 +2186,7 @@ void HeightMapShape3DSW::set_data(const Variant &p_data) { _setup(heights_buffer, width, depth, min_height, max_height); } -Variant HeightMapShape3DSW::get_data() const { +Variant GodotHeightMapShape3D::get_data() const { Dictionary d; d["width"] = width; d["depth"] = depth; @@ -2048,5 +2200,5 @@ Variant HeightMapShape3DSW::get_data() const { return d; } -HeightMapShape3DSW::HeightMapShape3DSW() { +GodotHeightMapShape3D::GodotHeightMapShape3D() { } diff --git a/servers/physics_3d/shape_3d_sw.h b/servers/physics_3d/godot_shape_3d.h index b05f65f268..43319510d4 100644 --- a/servers/physics_3d/shape_3d_sw.h +++ b/servers/physics_3d/godot_shape_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* shape_3d_sw.h */ +/* godot_shape_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,29 +28,30 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SHAPE_SW_H -#define SHAPE_SW_H +#ifndef GODOT_SHAPE_3D_H +#define GODOT_SHAPE_3D_H #include "core/math/geometry_3d.h" +#include "core/templates/local_vector.h" #include "servers/physics_server_3d.h" -class Shape3DSW; +class GodotShape3D; -class ShapeOwner3DSW { +class GodotShapeOwner3D { public: virtual void _shape_changed() = 0; - virtual void remove_shape(Shape3DSW *p_shape) = 0; + virtual void remove_shape(GodotShape3D *p_shape) = 0; - virtual ~ShapeOwner3DSW() {} + virtual ~GodotShapeOwner3D() {} }; -class Shape3DSW { +class GodotShape3D { RID self; AABB aabb; - bool configured; - real_t custom_bias; + bool configured = false; + real_t custom_bias = 0.0; - Map<ShapeOwner3DSW *, int> owners; + Map<GodotShapeOwner3D *, int> owners; protected: void configure(const AABB &p_aabb); @@ -63,7 +64,7 @@ public: FEATURE_CIRCLE, }; - virtual real_t get_area() const { return aabb.get_area(); } + virtual real_t get_volume() const { return aabb.get_volume(); } _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; } _FORCE_INLINE_ RID get_self() const { return self; } @@ -79,7 +80,7 @@ public: virtual Vector3 get_support(const Vector3 &p_normal) const; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const = 0; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const = 0; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const = 0; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, bool p_hit_back_faces) const = 0; virtual bool intersect_point(const Vector3 &p_point) const = 0; virtual Vector3 get_moment_of_inertia(real_t p_mass) const = 0; @@ -89,29 +90,29 @@ public: _FORCE_INLINE_ void set_custom_bias(real_t p_bias) { custom_bias = p_bias; } _FORCE_INLINE_ real_t get_custom_bias() const { return custom_bias; } - void add_owner(ShapeOwner3DSW *p_owner); - void remove_owner(ShapeOwner3DSW *p_owner); - bool is_owner(ShapeOwner3DSW *p_owner) const; - const Map<ShapeOwner3DSW *, int> &get_owners() const; + void add_owner(GodotShapeOwner3D *p_owner); + void remove_owner(GodotShapeOwner3D *p_owner); + bool is_owner(GodotShapeOwner3D *p_owner) const; + const Map<GodotShapeOwner3D *, int> &get_owners() const; - Shape3DSW(); - virtual ~Shape3DSW(); + GodotShape3D() {} + virtual ~GodotShape3D(); }; -class ConcaveShape3DSW : public Shape3DSW { +class GodotConcaveShape3D : public GodotShape3D { public: virtual bool is_concave() const override { return true; } virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; } // Returns true to stop the query. - typedef bool (*QueryCallback)(void *p_userdata, Shape3DSW *p_convex); + typedef bool (*QueryCallback)(void *p_userdata, GodotShape3D *p_convex); - virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const = 0; + virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const = 0; - ConcaveShape3DSW() {} + GodotConcaveShape3D() {} }; -class PlaneShape3DSW : public Shape3DSW { +class GodotWorldBoundaryShape3D : public GodotShape3D { Plane plane; void _setup(const Plane &p_plane); @@ -119,13 +120,13 @@ class PlaneShape3DSW : public Shape3DSW { public: Plane get_plane() const; - virtual real_t get_area() const override { return INFINITY; } - virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_PLANE; } + virtual real_t get_volume() const override { return INFINITY; } + virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_WORLD_BOUNDARY; } virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; } - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; virtual Vector3 get_moment_of_inertia(real_t p_mass) const override; @@ -133,12 +134,12 @@ public: virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - PlaneShape3DSW(); + GodotWorldBoundaryShape3D(); }; -class SeparationRayShape3DSW : public Shape3DSW { - real_t length; - bool slide_on_slope; +class GodotSeparationRayShape3D : public GodotShape3D { + real_t length = 1.0; + bool slide_on_slope = false; void _setup(real_t p_length, bool p_slide_on_slope); @@ -146,13 +147,13 @@ public: real_t get_length() const; bool get_slide_on_slope() const; - virtual real_t get_area() const override { return 0.0; } + virtual real_t get_volume() const override { return 0.0; } virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_SEPARATION_RAY; } virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; @@ -161,25 +162,25 @@ public: virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - SeparationRayShape3DSW(); + GodotSeparationRayShape3D(); }; -class SphereShape3DSW : public Shape3DSW { - real_t radius; +class GodotSphereShape3D : public GodotShape3D { + real_t radius = 0.0; void _setup(real_t p_radius); public: real_t get_radius() const; - virtual real_t get_area() const override { return 4.0 / 3.0 * Math_PI * radius * radius * radius; } + virtual real_t get_volume() const override { return 4.0 / 3.0 * Math_PI * radius * radius * radius; } virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_SPHERE; } virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; @@ -188,23 +189,23 @@ public: virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - SphereShape3DSW(); + GodotSphereShape3D(); }; -class BoxShape3DSW : public Shape3DSW { +class GodotBoxShape3D : public GodotShape3D { Vector3 half_extents; void _setup(const Vector3 &p_half_extents); public: _FORCE_INLINE_ Vector3 get_half_extents() const { return half_extents; } - virtual real_t get_area() const override { return 8 * half_extents.x * half_extents.y * half_extents.z; } + virtual real_t get_volume() const override { return 8 * half_extents.x * half_extents.y * half_extents.z; } virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_BOX; } virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; @@ -213,12 +214,12 @@ public: virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - BoxShape3DSW(); + GodotBoxShape3D(); }; -class CapsuleShape3DSW : public Shape3DSW { - real_t height; - real_t radius; +class GodotCapsuleShape3D : public GodotShape3D { + real_t height = 0.0; + real_t radius = 0.0; void _setup(real_t p_height, real_t p_radius); @@ -226,14 +227,14 @@ public: _FORCE_INLINE_ real_t get_height() const { return height; } _FORCE_INLINE_ real_t get_radius() const { return radius; } - virtual real_t get_area() const override { return 4.0 / 3.0 * Math_PI * radius * radius * radius + (height - radius * 2.0) * Math_PI * radius * radius; } + virtual real_t get_volume() const override { return 4.0 / 3.0 * Math_PI * radius * radius * radius + (height - radius * 2.0) * Math_PI * radius * radius; } virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CAPSULE; } virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; @@ -242,12 +243,12 @@ public: virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - CapsuleShape3DSW(); + GodotCapsuleShape3D(); }; -class CylinderShape3DSW : public Shape3DSW { - real_t height; - real_t radius; +class GodotCylinderShape3D : public GodotShape3D { + real_t height = 0.0; + real_t radius = 0.0; void _setup(real_t p_height, real_t p_radius); @@ -255,14 +256,14 @@ public: _FORCE_INLINE_ real_t get_height() const { return height; } _FORCE_INLINE_ real_t get_radius() const { return radius; } - virtual real_t get_area() const override { return 4.0 / 3.0 * Math_PI * radius * radius * radius + height * Math_PI * radius * radius; } + virtual real_t get_volume() const override { return height * Math_PI * radius * radius; } virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CYLINDER; } virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; @@ -271,10 +272,10 @@ public: virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - CylinderShape3DSW(); + GodotCylinderShape3D(); }; -struct ConvexPolygonShape3DSW : public Shape3DSW { +struct GodotConvexPolygonShape3D : public GodotShape3D { Geometry3D::MeshData mesh; void _setup(const Vector<Vector3> &p_vertices); @@ -287,7 +288,7 @@ public: virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; @@ -296,18 +297,18 @@ public: virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - ConvexPolygonShape3DSW(); + GodotConvexPolygonShape3D(); }; -struct _VolumeSW_BVH; -struct FaceShape3DSW; +struct _Volume_BVH; +struct GodotFaceShape3D; -struct ConcavePolygonShape3DSW : public ConcaveShape3DSW { +struct GodotConcavePolygonShape3D : public GodotConcaveShape3D { // always a trimesh struct Face { Vector3 normal; - int indices[3]; + int indices[3] = {}; }; Vector<Face> faces; @@ -315,10 +316,10 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW { struct BVH { AABB aabb; - int left; - int right; + int left = 0; + int right = 0; - int face_index; + int face_index = 0; }; Vector<BVH> bvh; @@ -330,7 +331,7 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW { const Face *faces = nullptr; const Vector3 *vertices = nullptr; const BVH *bvh = nullptr; - FaceShape3DSW *face = nullptr; + GodotFaceShape3D *face = nullptr; }; struct _SegmentCullParams { @@ -340,7 +341,7 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW { const Face *faces = nullptr; const Vector3 *vertices = nullptr; const BVH *bvh = nullptr; - FaceShape3DSW *face = nullptr; + GodotFaceShape3D *face = nullptr; Vector3 result; Vector3 normal; @@ -353,7 +354,7 @@ struct ConcavePolygonShape3DSW : public ConcaveShape3DSW { void _cull_segment(int p_idx, _SegmentCullParams *p_params) const; bool _cull(int p_idx, _CullParams *p_params) const; - void _fill_bvh(_VolumeSW_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx); + void _fill_bvh(_Volume_BVH *p_bvh_tree, BVH *p_bvh_array, int &p_idx); void _setup(const Vector<Vector3> &p_faces, bool p_backface_collision); @@ -365,26 +366,41 @@ public: virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; - virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const override; + virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const override; virtual Vector3 get_moment_of_inertia(real_t p_mass) const override; virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - ConcavePolygonShape3DSW(); + GodotConcavePolygonShape3D(); }; -struct HeightMapShape3DSW : public ConcaveShape3DSW { +struct GodotHeightMapShape3D : public GodotConcaveShape3D { Vector<real_t> heights; int width = 0; int depth = 0; Vector3 local_origin; + // Accelerator. + struct Range { + real_t min = 0.0; + real_t max = 0.0; + }; + LocalVector<Range> bounds_grid; + int bounds_grid_width = 0; + int bounds_grid_depth = 0; + + static const int BOUNDS_CHUNK_SIZE = 16; + + _FORCE_INLINE_ const Range &_get_bounds_chunk(int p_x, int p_z) const { + return bounds_grid[(p_z * bounds_grid_width) + p_x]; + } + _FORCE_INLINE_ real_t _get_height(int p_x, int p_z) const { return heights[(p_z * width) + p_x]; } @@ -397,6 +413,11 @@ struct HeightMapShape3DSW : public ConcaveShape3DSW { void _get_cell(const Vector3 &p_point, int &r_x, int &r_y, int &r_z) const; + void _build_accelerator(); + + template <typename ProcessFunction> + bool _intersect_grid_segment(ProcessFunction &p_process, const Vector3 &p_begin, const Vector3 &p_end, int p_width, int p_depth, const Vector3 &offset, Vector3 &r_point, Vector3 &r_normal) const; + void _setup(const Vector<real_t> &p_heights, int p_width, int p_depth, real_t p_min_height, real_t p_max_height); public: @@ -408,25 +429,26 @@ public: virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; - virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata) const override; + virtual void cull(const AABB &p_local_aabb, QueryCallback p_callback, void *p_userdata, bool p_invert_backface_collision) const override; virtual Vector3 get_moment_of_inertia(real_t p_mass) const override; virtual void set_data(const Variant &p_data) override; virtual Variant get_data() const override; - HeightMapShape3DSW(); + GodotHeightMapShape3D(); }; //used internally -struct FaceShape3DSW : public Shape3DSW { +struct GodotFaceShape3D : public GodotShape3D { Vector3 normal; //cache Vector3 vertex[3]; bool backface_collision = false; + bool invert_backface_collision = false; virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONCAVE_POLYGON; } @@ -435,7 +457,7 @@ struct FaceShape3DSW : public Shape3DSW { virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override; virtual Vector3 get_support(const Vector3 &p_normal) const override; virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override; - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override; + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; virtual bool intersect_point(const Vector3 &p_point) const override; virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; @@ -444,11 +466,11 @@ struct FaceShape3DSW : public Shape3DSW { virtual void set_data(const Variant &p_data) override {} virtual Variant get_data() const override { return Variant(); } - FaceShape3DSW(); + GodotFaceShape3D(); }; -struct MotionShape3DSW : public Shape3DSW { - Shape3DSW *shape; +struct GodotMotionShape3D : public GodotShape3D { + GodotShape3D *shape = nullptr; Vector3 motion; virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_CONVEX_POLYGON; } @@ -474,7 +496,7 @@ struct MotionShape3DSW : public Shape3DSW { } virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; } - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const override { return false; } + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override { return false; } virtual bool intersect_point(const Vector3 &p_point) const override { return false; } virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override { return p_point; } @@ -483,7 +505,7 @@ struct MotionShape3DSW : public Shape3DSW { virtual void set_data(const Variant &p_data) override {} virtual Variant get_data() const override { return Variant(); } - MotionShape3DSW() { configure(AABB()); } + GodotMotionShape3D() { configure(AABB()); } }; -#endif // SHAPE_SW_H +#endif // GODOT_SHAPE_3D_H diff --git a/servers/physics_3d/soft_body_3d_sw.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index d7e13867bf..43d4433302 100644 --- a/servers/physics_3d/soft_body_3d_sw.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* soft_body_3d_sw.cpp */ +/* godot_soft_body_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,17 +28,19 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "soft_body_3d_sw.h" -#include "space_3d_sw.h" +#include "godot_soft_body_3d.h" + +#include "godot_space_3d.h" #include "core/math/geometry_3d.h" #include "core/templates/map.h" +#include "servers/rendering_server.h" // Based on Bullet soft body. /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -52,16 +54,16 @@ subject to the following restrictions: */ ///btSoftBody implementation by Nathanael Presson -SoftBody3DSW::SoftBody3DSW() : - CollisionObject3DSW(TYPE_SOFT_BODY), +GodotSoftBody3D::GodotSoftBody3D() : + GodotCollisionObject3D(TYPE_SOFT_BODY), active_list(this) { _set_static(false); } -void SoftBody3DSW::_shapes_changed() { +void GodotSoftBody3D::_shapes_changed() { } -void SoftBody3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) { +void GodotSoftBody3D::set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant) { switch (p_state) { case PhysicsServer3D::BODY_STATE_TRANSFORM: { _set_transform(p_variant); @@ -86,7 +88,7 @@ void SoftBody3DSW::set_state(PhysicsServer3D::BodyState p_state, const Variant & } } -Variant SoftBody3DSW::get_state(PhysicsServer3D::BodyState p_state) const { +Variant GodotSoftBody3D::get_state(PhysicsServer3D::BodyState p_state) const { switch (p_state) { case PhysicsServer3D::BODY_STATE_TRANSFORM: { return get_transform(); @@ -109,7 +111,7 @@ Variant SoftBody3DSW::get_state(PhysicsServer3D::BodyState p_state) const { return Variant(); } -void SoftBody3DSW::set_space(Space3DSW *p_space) { +void GodotSoftBody3D::set_space(GodotSpace3D *p_space) { if (get_space()) { get_space()->soft_body_remove_from_active_list(&active_list); @@ -127,7 +129,7 @@ void SoftBody3DSW::set_space(Space3DSW *p_space) { } } -void SoftBody3DSW::set_mesh(const Ref<Mesh> &p_mesh) { +void GodotSoftBody3D::set_mesh(RID p_mesh) { destroy(); soft_mesh = p_mesh; @@ -136,17 +138,16 @@ void SoftBody3DSW::set_mesh(const Ref<Mesh> &p_mesh) { return; } - Array arrays = soft_mesh->surface_get_arrays(0); - ERR_FAIL_COND(!(soft_mesh->surface_get_format(0) & RS::ARRAY_FORMAT_INDEX)); + Array arrays = RenderingServer::get_singleton()->mesh_surface_get_arrays(soft_mesh, 0); + ERR_FAIL_COND(arrays.is_empty()); - bool success = create_from_trimesh(arrays[RS::ARRAY_INDEX], arrays[RS::ARRAY_VERTEX]); + bool success = create_from_trimesh(arrays[RenderingServer::ARRAY_INDEX], arrays[RenderingServer::ARRAY_VERTEX]); if (!success) { destroy(); - soft_mesh = Ref<Mesh>(); } } -void SoftBody3DSW::update_rendering_server(RenderingServerHandler *p_rendering_server_handler) { +void GodotSoftBody3D::update_rendering_server(RenderingServerHandler *p_rendering_server_handler) { if (soft_mesh.is_null()) { return; } @@ -165,7 +166,7 @@ void SoftBody3DSW::update_rendering_server(RenderingServerHandler *p_rendering_s p_rendering_server_handler->set_aabb(bounds); } -void SoftBody3DSW::update_normals_and_centroids() { +void GodotSoftBody3D::update_normals_and_centroids() { uint32_t i, ni; for (i = 0, ni = nodes.size(); i < ni; ++i) { @@ -192,7 +193,7 @@ void SoftBody3DSW::update_normals_and_centroids() { } } -void SoftBody3DSW::update_bounds() { +void GodotSoftBody3D::update_bounds() { AABB prev_bounds = bounds; prev_bounds.grow_by(collision_margin); @@ -224,13 +225,13 @@ void SoftBody3DSW::update_bounds() { } } -void SoftBody3DSW::update_constants() { +void GodotSoftBody3D::update_constants() { reset_link_rest_lengths(); update_link_constants(); update_area(); } -void SoftBody3DSW::update_area() { +void GodotSoftBody3D::update_area() { int i, ni; // Face area. @@ -249,8 +250,10 @@ void SoftBody3DSW::update_area() { // Node area. LocalVector<int> counts; - counts.resize(nodes.size()); - memset(counts.ptr(), 0, counts.size() * sizeof(int)); + if (nodes.size() > 0) { + counts.resize(nodes.size()); + memset(counts.ptr(), 0, counts.size() * sizeof(int)); + } for (i = 0, ni = nodes.size(); i < ni; ++i) { nodes[i].area = 0.0; @@ -274,7 +277,7 @@ void SoftBody3DSW::update_area() { } } -void SoftBody3DSW::reset_link_rest_lengths() { +void GodotSoftBody3D::reset_link_rest_lengths() { for (uint32_t i = 0, ni = links.size(); i < ni; ++i) { Link &link = links[i]; link.rl = (link.n[0]->x - link.n[1]->x).length(); @@ -282,7 +285,7 @@ void SoftBody3DSW::reset_link_rest_lengths() { } } -void SoftBody3DSW::update_link_constants() { +void GodotSoftBody3D::update_link_constants() { real_t inv_linear_stiffness = 1.0 / linear_stiffness; for (uint32_t i = 0, ni = links.size(); i < ni; ++i) { Link &link = links[i]; @@ -290,7 +293,7 @@ void SoftBody3DSW::update_link_constants() { } } -void SoftBody3DSW::apply_nodes_transform(const Transform3D &p_transform) { +void GodotSoftBody3D::apply_nodes_transform(const Transform3D &p_transform) { if (soft_mesh.is_null()) { return; } @@ -316,24 +319,28 @@ void SoftBody3DSW::apply_nodes_transform(const Transform3D &p_transform) { update_constants(); } -Vector3 SoftBody3DSW::get_vertex_position(int p_index) const { +Vector3 GodotSoftBody3D::get_vertex_position(int p_index) const { + ERR_FAIL_COND_V(p_index < 0, Vector3()); + if (soft_mesh.is_null()) { return Vector3(); } - ERR_FAIL_INDEX_V(p_index, (int)map_visual_to_physics.size(), Vector3()); + ERR_FAIL_COND_V(p_index >= (int)map_visual_to_physics.size(), Vector3()); uint32_t node_index = map_visual_to_physics[p_index]; ERR_FAIL_COND_V(node_index >= nodes.size(), Vector3()); return nodes[node_index].x; } -void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) { +void GodotSoftBody3D::set_vertex_position(int p_index, const Vector3 &p_position) { + ERR_FAIL_COND(p_index < 0); + if (soft_mesh.is_null()) { return; } - ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size()); + ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size()); uint32_t node_index = map_visual_to_physics[p_index]; ERR_FAIL_COND(node_index >= nodes.size()); @@ -342,7 +349,9 @@ void SoftBody3DSW::set_vertex_position(int p_index, const Vector3 &p_position) { node.x = p_position; } -void SoftBody3DSW::pin_vertex(int p_index) { +void GodotSoftBody3D::pin_vertex(int p_index) { + ERR_FAIL_COND(p_index < 0); + if (is_vertex_pinned(p_index)) { return; } @@ -350,7 +359,7 @@ void SoftBody3DSW::pin_vertex(int p_index) { pinned_vertices.push_back(p_index); if (!soft_mesh.is_null()) { - ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size()); + ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size()); uint32_t node_index = map_visual_to_physics[p_index]; ERR_FAIL_COND(node_index >= nodes.size()); @@ -359,14 +368,16 @@ void SoftBody3DSW::pin_vertex(int p_index) { } } -void SoftBody3DSW::unpin_vertex(int p_index) { +void GodotSoftBody3D::unpin_vertex(int p_index) { + ERR_FAIL_COND(p_index < 0); + uint32_t pinned_count = pinned_vertices.size(); for (uint32_t i = 0; i < pinned_count; ++i) { if (p_index == pinned_vertices[i]) { - pinned_vertices.remove(i); + pinned_vertices.remove_at(i); if (!soft_mesh.is_null()) { - ERR_FAIL_INDEX(p_index, (int)map_visual_to_physics.size()); + ERR_FAIL_COND(p_index >= (int)map_visual_to_physics.size()); uint32_t node_index = map_visual_to_physics[p_index]; ERR_FAIL_COND(node_index >= nodes.size()); @@ -381,15 +392,15 @@ void SoftBody3DSW::unpin_vertex(int p_index) { } } -void SoftBody3DSW::unpin_all_vertices() { +void GodotSoftBody3D::unpin_all_vertices() { if (!soft_mesh.is_null()) { real_t inv_node_mass = nodes.size() * inv_total_mass; uint32_t pinned_count = pinned_vertices.size(); for (uint32_t i = 0; i < pinned_count; ++i) { - uint32_t vertex_index = pinned_vertices[i]; + int pinned_vertex = pinned_vertices[i]; - ERR_CONTINUE(vertex_index >= map_visual_to_physics.size()); - uint32_t node_index = map_visual_to_physics[vertex_index]; + ERR_CONTINUE(pinned_vertex >= (int)map_visual_to_physics.size()); + uint32_t node_index = map_visual_to_physics[pinned_vertex]; ERR_CONTINUE(node_index >= nodes.size()); Node &node = nodes[node_index]; @@ -400,7 +411,9 @@ void SoftBody3DSW::unpin_all_vertices() { pinned_vertices.clear(); } -bool SoftBody3DSW::is_vertex_pinned(int p_index) const { +bool GodotSoftBody3D::is_vertex_pinned(int p_index) const { + ERR_FAIL_COND_V(p_index < 0, false); + uint32_t pinned_count = pinned_vertices.size(); for (uint32_t i = 0; i < pinned_count; ++i) { if (p_index == pinned_vertices[i]) { @@ -411,47 +424,47 @@ bool SoftBody3DSW::is_vertex_pinned(int p_index) const { return false; } -uint32_t SoftBody3DSW::get_node_count() const { +uint32_t GodotSoftBody3D::get_node_count() const { return nodes.size(); } -real_t SoftBody3DSW::get_node_inv_mass(uint32_t p_node_index) const { +real_t GodotSoftBody3D::get_node_inv_mass(uint32_t p_node_index) const { ERR_FAIL_COND_V(p_node_index >= nodes.size(), 0.0); return nodes[p_node_index].im; } -Vector3 SoftBody3DSW::get_node_position(uint32_t p_node_index) const { +Vector3 GodotSoftBody3D::get_node_position(uint32_t p_node_index) const { ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3()); return nodes[p_node_index].x; } -Vector3 SoftBody3DSW::get_node_velocity(uint32_t p_node_index) const { +Vector3 GodotSoftBody3D::get_node_velocity(uint32_t p_node_index) const { ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3()); return nodes[p_node_index].v; } -Vector3 SoftBody3DSW::get_node_biased_velocity(uint32_t p_node_index) const { +Vector3 GodotSoftBody3D::get_node_biased_velocity(uint32_t p_node_index) const { ERR_FAIL_COND_V(p_node_index >= nodes.size(), Vector3()); return nodes[p_node_index].bv; } -void SoftBody3DSW::apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse) { +void GodotSoftBody3D::apply_node_impulse(uint32_t p_node_index, const Vector3 &p_impulse) { ERR_FAIL_COND(p_node_index >= nodes.size()); Node &node = nodes[p_node_index]; node.v += p_impulse * node.im; } -void SoftBody3DSW::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) { +void GodotSoftBody3D::apply_node_bias_impulse(uint32_t p_node_index, const Vector3 &p_impulse) { ERR_FAIL_COND(p_node_index >= nodes.size()); Node &node = nodes[p_node_index]; node.bv += p_impulse * node.im; } -uint32_t SoftBody3DSW::get_face_count() const { +uint32_t GodotSoftBody3D::get_face_count() const { return faces.size(); } -void SoftBody3DSW::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const { +void GodotSoftBody3D::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Vector3 &r_point_2, Vector3 &r_point_3) const { ERR_FAIL_COND(p_face_index >= faces.size()); const Face &face = faces[p_face_index]; r_point_1 = face.n[0]->x; @@ -459,12 +472,15 @@ void SoftBody3DSW::get_face_points(uint32_t p_face_index, Vector3 &r_point_1, Ve r_point_3 = face.n[2]->x; } -Vector3 SoftBody3DSW::get_face_normal(uint32_t p_face_index) const { +Vector3 GodotSoftBody3D::get_face_normal(uint32_t p_face_index) const { ERR_FAIL_COND_V(p_face_index >= faces.size(), Vector3()); return faces[p_face_index].normal; } -bool SoftBody3DSW::create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices) { +bool GodotSoftBody3D::create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices) { + ERR_FAIL_COND_V(p_indices.is_empty(), false); + ERR_FAIL_COND_V(p_vertices.is_empty(), false); + uint32_t node_count = 0; LocalVector<Vector3> vertices; const int visual_vertex_count(p_vertices.size()); @@ -581,7 +597,7 @@ bool SoftBody3DSW::create_from_trimesh(const Vector<int> &p_indices, const Vecto return true; } -void SoftBody3DSW::generate_bending_constraints(int p_distance) { +void GodotSoftBody3D::generate_bending_constraints(int p_distance) { uint32_t i, j; if (p_distance > 1) { @@ -694,13 +710,15 @@ void SoftBody3DSW::generate_bending_constraints(int p_distance) { // A small structure to track lists of dependent link calculations. class LinkDeps { public: - int value; // A link calculation that is dependent on this one - // Positive values = "input A" while negative values = "input B" - LinkDeps *next; // Next dependence in the list + // A link calculation that is dependent on this one. + // Positive values = "input A" while negative values = "input B". + int value; + // Next dependence in the list. + LinkDeps *next; }; typedef LinkDeps *LinkDepsPtr; -void SoftBody3DSW::reoptimize_link_order() { +void GodotSoftBody3D::reoptimize_link_order() { const int reop_not_dependent = -1; const int reop_node_complete = -2; @@ -809,7 +827,7 @@ void SoftBody3DSW::reoptimize_link_order() { memdelete_arr(link_buffer); } -void SoftBody3DSW::append_link(uint32_t p_node1, uint32_t p_node2) { +void GodotSoftBody3D::append_link(uint32_t p_node1, uint32_t p_node2) { if (p_node1 == p_node2) { return; } @@ -825,7 +843,7 @@ void SoftBody3DSW::append_link(uint32_t p_node1, uint32_t p_node2) { links.push_back(link); } -void SoftBody3DSW::append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3) { +void GodotSoftBody3D::append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_node3) { if (p_node1 == p_node2) { return; } @@ -850,11 +868,11 @@ void SoftBody3DSW::append_face(uint32_t p_node1, uint32_t p_node2, uint32_t p_no faces.push_back(face); } -void SoftBody3DSW::set_iteration_count(int p_val) { +void GodotSoftBody3D::set_iteration_count(int p_val) { iteration_count = p_val; } -void SoftBody3DSW::set_total_mass(real_t p_val) { +void GodotSoftBody3D::set_total_mass(real_t p_val) { ERR_FAIL_COND(p_val < 0.0); inv_total_mass = 1.0 / p_val; @@ -870,27 +888,27 @@ void SoftBody3DSW::set_total_mass(real_t p_val) { update_constants(); } -void SoftBody3DSW::set_collision_margin(real_t p_val) { +void GodotSoftBody3D::set_collision_margin(real_t p_val) { collision_margin = p_val; } -void SoftBody3DSW::set_linear_stiffness(real_t p_val) { +void GodotSoftBody3D::set_linear_stiffness(real_t p_val) { linear_stiffness = p_val; } -void SoftBody3DSW::set_pressure_coefficient(real_t p_val) { +void GodotSoftBody3D::set_pressure_coefficient(real_t p_val) { pressure_coefficient = p_val; } -void SoftBody3DSW::set_damping_coefficient(real_t p_val) { +void GodotSoftBody3D::set_damping_coefficient(real_t p_val) { damping_coefficient = p_val; } -void SoftBody3DSW::set_drag_coefficient(real_t p_val) { +void GodotSoftBody3D::set_drag_coefficient(real_t p_val) { drag_coefficient = p_val; } -void SoftBody3DSW::add_velocity(const Vector3 &p_velocity) { +void GodotSoftBody3D::add_velocity(const Vector3 &p_velocity) { for (uint32_t i = 0, ni = nodes.size(); i < ni; ++i) { Node &node = nodes[i]; if (node.im > 0) { @@ -899,9 +917,7 @@ void SoftBody3DSW::add_velocity(const Vector3 &p_velocity) { } } -void SoftBody3DSW::apply_forces(bool p_has_wind_forces) { - int ac = areas.size(); - +void GodotSoftBody3D::apply_forces(const LocalVector<GodotArea3D *> &p_wind_areas) { if (nodes.is_empty()) { return; } @@ -914,7 +930,6 @@ void SoftBody3DSW::apply_forces(bool p_has_wind_forces) { // Iterate over faces (try not to iterate elsewhere if possible). for (i = 0, ni = faces.size(); i < ni; ++i) { - bool stopped = false; const Face &face = faces[i]; Vector3 wind_force(0, 0, 0); @@ -923,24 +938,10 @@ void SoftBody3DSW::apply_forces(bool p_has_wind_forces) { volume += vec3_dot(face.n[0]->x - org, vec3_cross(face.n[1]->x - org, face.n[2]->x - org)); // Compute nodal forces from area winds. - if (ac && p_has_wind_forces) { - const AreaCMP *aa = &areas[0]; - for (j = ac - 1; j >= 0 && !stopped; j--) { - PhysicsServer3D::AreaSpaceOverrideMode mode = aa[j].area->get_space_override_mode(); - switch (mode) { - case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: - case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { - wind_force += _compute_area_windforce(aa[j].area, &face); - stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; - } break; - case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: - case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { - wind_force = _compute_area_windforce(aa[j].area, &face); - stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; - } break; - default: { - } - } + int wind_area_count = p_wind_areas.size(); + if (wind_area_count > 0) { + for (j = 0; j < wind_area_count; j++) { + wind_force += _compute_area_windforce(p_wind_areas[j], &face); } for (j = 0; j < 3; j++) { @@ -963,13 +964,7 @@ void SoftBody3DSW::apply_forces(bool p_has_wind_forces) { } } -void SoftBody3DSW::_compute_area_gravity(const Area3DSW *p_area) { - Vector3 area_gravity; - p_area->compute_gravity(get_transform().get_origin(), area_gravity); - gravity += area_gravity; -} - -Vector3 SoftBody3DSW::_compute_area_windforce(const Area3DSW *p_area, const Face *p_face) { +Vector3 GodotSoftBody3D::_compute_area_windforce(const GodotArea3D *p_area, const Face *p_face) { real_t wfm = p_area->get_wind_force_magnitude(); real_t waf = p_area->get_wind_attenuation_factor(); const Vector3 &wd = p_area->get_wind_direction(); @@ -981,49 +976,64 @@ Vector3 SoftBody3DSW::_compute_area_windforce(const Area3DSW *p_area, const Face return nodal_force_magnitude * p_face->normal; } -void SoftBody3DSW::predict_motion(real_t p_delta) { +void GodotSoftBody3D::predict_motion(real_t p_delta) { const real_t inv_delta = 1.0 / p_delta; ERR_FAIL_COND(!get_space()); - Area3DSW *def_area = get_space()->get_default_area(); - ERR_FAIL_COND(!def_area); - gravity = def_area->get_gravity_vector() * def_area->get_gravity(); + bool gravity_done = false; + Vector3 gravity; - int ac = areas.size(); - bool stopped = false; - bool has_wind_forces = false; + LocalVector<GodotArea3D *> wind_areas; + int ac = areas.size(); if (ac) { areas.sort(); const AreaCMP *aa = &areas[0]; - for (int i = ac - 1; i >= 0 && !stopped; i--) { - // Avoids unnecessary loop in apply_forces(). - has_wind_forces = has_wind_forces || aa[i].area->get_wind_force_magnitude() > CMP_EPSILON; - - PhysicsServer3D::AreaSpaceOverrideMode mode = aa[i].area->get_space_override_mode(); - switch (mode) { - case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: - case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { - _compute_area_gravity(aa[i].area); - stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; - } break; - case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: - case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { - gravity = Vector3(0, 0, 0); - _compute_area_gravity(aa[i].area); - stopped = mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; - } break; - default: { + for (int i = ac - 1; i >= 0; i--) { + if (!gravity_done) { + PhysicsServer3D::AreaSpaceOverrideMode area_gravity_mode = (PhysicsServer3D::AreaSpaceOverrideMode)(int)aa[i].area->get_param(PhysicsServer3D::AREA_PARAM_GRAVITY_OVERRIDE_MODE); + if (area_gravity_mode != PhysicsServer3D::AREA_SPACE_OVERRIDE_DISABLED) { + Vector3 area_gravity; + aa[i].area->compute_gravity(get_transform().get_origin(), area_gravity); + switch (area_gravity_mode) { + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE: { + gravity += area_gravity; + gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_COMBINE_REPLACE; + } break; + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE: + case PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE_COMBINE: { + gravity = Vector3(0, 0, 0); + gravity = area_gravity; + gravity_done = area_gravity_mode == PhysicsServer3D::AREA_SPACE_OVERRIDE_REPLACE; + } break; + default: { + } + } } } + + if (aa[i].area->get_wind_force_magnitude() > CMP_EPSILON) { + wind_areas.push_back(aa[i].area); + } } } + // Add default gravity and damping from space area. + if (!gravity_done) { + GodotArea3D *default_area = get_space()->get_default_area(); + ERR_FAIL_COND(!default_area); + + Vector3 default_gravity; + default_area->compute_gravity(get_transform().get_origin(), default_gravity); + gravity += default_gravity; + } + // Apply forces. add_velocity(gravity * p_delta); - if (pressure_coefficient > CMP_EPSILON || has_wind_forces) { - apply_forces(has_wind_forces); + if (pressure_coefficient > CMP_EPSILON || !wind_areas.is_empty()) { + apply_forces(wind_areas); } // Avoid soft body from 'exploding' so use some upper threshold of maximum motion @@ -1069,7 +1079,7 @@ void SoftBody3DSW::predict_motion(real_t p_delta) { face_tree.optimize_incremental(1); } -void SoftBody3DSW::solve_constraints(real_t p_delta) { +void GodotSoftBody3D::solve_constraints(real_t p_delta) { const real_t inv_delta = 1.0 / p_delta; uint32_t i, ni; @@ -1106,7 +1116,7 @@ void SoftBody3DSW::solve_constraints(real_t p_delta) { update_normals_and_centroids(); } -void SoftBody3DSW::solve_links(real_t kst, real_t ti) { +void GodotSoftBody3D::solve_links(real_t kst, real_t ti) { for (uint32_t i = 0, ni = links.size(); i < ni; ++i) { Link &link = links[i]; if (link.c0 > 0) { @@ -1124,16 +1134,16 @@ void SoftBody3DSW::solve_links(real_t kst, real_t ti) { } struct AABBQueryResult { - const SoftBody3DSW *soft_body = nullptr; + const GodotSoftBody3D *soft_body = nullptr; void *userdata = nullptr; - SoftBody3DSW::QueryResultCallback result_callback = nullptr; + GodotSoftBody3D::QueryResultCallback result_callback = nullptr; _FORCE_INLINE_ bool operator()(void *p_data) { return result_callback(soft_body->get_node_index(p_data), userdata); }; }; -void SoftBody3DSW::query_aabb(const AABB &p_aabb, SoftBody3DSW::QueryResultCallback p_result_callback, void *p_userdata) { +void GodotSoftBody3D::query_aabb(const AABB &p_aabb, GodotSoftBody3D::QueryResultCallback p_result_callback, void *p_userdata) { AABBQueryResult query_result; query_result.soft_body = this; query_result.result_callback = p_result_callback; @@ -1143,16 +1153,16 @@ void SoftBody3DSW::query_aabb(const AABB &p_aabb, SoftBody3DSW::QueryResultCallb } struct RayQueryResult { - const SoftBody3DSW *soft_body = nullptr; + const GodotSoftBody3D *soft_body = nullptr; void *userdata = nullptr; - SoftBody3DSW::QueryResultCallback result_callback = nullptr; + GodotSoftBody3D::QueryResultCallback result_callback = nullptr; _FORCE_INLINE_ bool operator()(void *p_data) { return result_callback(soft_body->get_face_index(p_data), userdata); }; }; -void SoftBody3DSW::query_ray(const Vector3 &p_from, const Vector3 &p_to, SoftBody3DSW::QueryResultCallback p_result_callback, void *p_userdata) { +void GodotSoftBody3D::query_ray(const Vector3 &p_from, const Vector3 &p_to, GodotSoftBody3D::QueryResultCallback p_result_callback, void *p_userdata) { if (face_tree.is_empty()) { initialize_face_tree(); } @@ -1165,7 +1175,7 @@ void SoftBody3DSW::query_ray(const Vector3 &p_from, const Vector3 &p_to, SoftBod face_tree.ray_query(p_from, p_to, query_result); } -void SoftBody3DSW::initialize_face_tree() { +void GodotSoftBody3D::initialize_face_tree() { face_tree.clear(); for (uint32_t i = 0; i < faces.size(); ++i) { Face &face = faces[i]; @@ -1182,7 +1192,7 @@ void SoftBody3DSW::initialize_face_tree() { } } -void SoftBody3DSW::update_face_tree(real_t p_delta) { +void GodotSoftBody3D::update_face_tree(real_t p_delta) { for (uint32_t i = 0; i < faces.size(); ++i) { const Face &face = faces[i]; @@ -1206,25 +1216,27 @@ void SoftBody3DSW::update_face_tree(real_t p_delta) { } } -void SoftBody3DSW::initialize_shape(bool p_force_move) { +void GodotSoftBody3D::initialize_shape(bool p_force_move) { if (get_shape_count() == 0) { - SoftBodyShape3DSW *soft_body_shape = memnew(SoftBodyShape3DSW(this)); + GodotSoftBodyShape3D *soft_body_shape = memnew(GodotSoftBodyShape3D(this)); add_shape(soft_body_shape); } else if (p_force_move) { - SoftBodyShape3DSW *soft_body_shape = static_cast<SoftBodyShape3DSW *>(get_shape(0)); + GodotSoftBodyShape3D *soft_body_shape = static_cast<GodotSoftBodyShape3D *>(get_shape(0)); soft_body_shape->update_bounds(); } } -void SoftBody3DSW::deinitialize_shape() { +void GodotSoftBody3D::deinitialize_shape() { if (get_shape_count() > 0) { - Shape3DSW *shape = get_shape(0); + GodotShape3D *shape = get_shape(0); remove_shape(shape); memdelete(shape); } } -void SoftBody3DSW::destroy() { +void GodotSoftBody3D::destroy() { + soft_mesh = RID(); + map_visual_to_physics.clear(); node_tree.clear(); @@ -1238,7 +1250,7 @@ void SoftBody3DSW::destroy() { deinitialize_shape(); } -void SoftBodyShape3DSW::update_bounds() { +void GodotSoftBodyShape3D::update_bounds() { ERR_FAIL_COND(!soft_body); AABB collision_aabb = soft_body->get_bounds(); @@ -1246,13 +1258,13 @@ void SoftBodyShape3DSW::update_bounds() { configure(collision_aabb); } -SoftBodyShape3DSW::SoftBodyShape3DSW(SoftBody3DSW *p_soft_body) { +GodotSoftBodyShape3D::GodotSoftBodyShape3D(GodotSoftBody3D *p_soft_body) { soft_body = p_soft_body; update_bounds(); } struct _SoftBodyIntersectSegmentInfo { - const SoftBody3DSW *soft_body = nullptr; + const GodotSoftBody3D *soft_body = nullptr; Vector3 from; Vector3 dir; Vector3 hit_position; @@ -1280,7 +1292,7 @@ struct _SoftBodyIntersectSegmentInfo { } }; -bool SoftBodyShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const { +bool GodotSoftBodyShape3D::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const { _SoftBodyIntersectSegmentInfo query_info; query_info.soft_body = soft_body; query_info.from = p_begin; @@ -1297,10 +1309,10 @@ bool SoftBodyShape3DSW::intersect_segment(const Vector3 &p_begin, const Vector3 return false; } -bool SoftBodyShape3DSW::intersect_point(const Vector3 &p_point) const { +bool GodotSoftBodyShape3D::intersect_point(const Vector3 &p_point) const { return false; } -Vector3 SoftBodyShape3DSW::get_closest_point_to(const Vector3 &p_point) const { +Vector3 GodotSoftBodyShape3D::get_closest_point_to(const Vector3 &p_point) const { ERR_FAIL_V_MSG(Vector3(), "Get closest point is not supported for soft bodies."); } diff --git a/servers/physics_3d/soft_body_3d_sw.h b/servers/physics_3d/godot_soft_body_3d.h index 58fd234fde..14ddc419cf 100644 --- a/servers/physics_3d/soft_body_3d_sw.h +++ b/servers/physics_3d/godot_soft_body_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* soft_body_3d_sw.h */ +/* godot_soft_body_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,11 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SOFT_BODY_3D_SW_H -#define SOFT_BODY_3D_SW_H +#ifndef GODOT_SOFT_BODY_3D_H +#define GODOT_SOFT_BODY_3D_H -#include "area_3d_sw.h" -#include "collision_object_3d_sw.h" +#include "godot_area_3d.h" +#include "godot_collision_object_3d.h" #include "core/math/aabb.h" #include "core/math/dynamic_bvh.h" @@ -40,12 +40,11 @@ #include "core/templates/local_vector.h" #include "core/templates/set.h" #include "core/templates/vset.h" -#include "scene/resources/mesh.h" -class Constraint3DSW; +class GodotConstraint3D; -class SoftBody3DSW : public CollisionObject3DSW { - Ref<Mesh> soft_mesh; +class GodotSoftBody3D : public GodotCollisionObject3D { + RID soft_mesh; struct Node { Vector3 s; // Source position @@ -102,11 +101,9 @@ class SoftBody3DSW : public CollisionObject3DSW { real_t drag_coefficient = 0.0; // [0,1] LocalVector<int> pinned_vertices; - Vector3 gravity; + SelfList<GodotSoftBody3D> active_list; - SelfList<SoftBody3DSW> active_list; - - Set<Constraint3DSW *> constraints; + Set<GodotConstraint3D *> constraints; Vector<AreaCMP> areas; @@ -114,20 +111,19 @@ class SoftBody3DSW : public CollisionObject3DSW { uint64_t island_step = 0; - _FORCE_INLINE_ void _compute_area_gravity(const Area3DSW *p_area); - _FORCE_INLINE_ Vector3 _compute_area_windforce(const Area3DSW *p_area, const Face *p_face); + _FORCE_INLINE_ Vector3 _compute_area_windforce(const GodotArea3D *p_area, const Face *p_face); public: - SoftBody3DSW(); + GodotSoftBody3D(); const AABB &get_bounds() const { return bounds; } void set_state(PhysicsServer3D::BodyState p_state, const Variant &p_variant); Variant get_state(PhysicsServer3D::BodyState p_state) const; - _FORCE_INLINE_ void add_constraint(Constraint3DSW *p_constraint) { constraints.insert(p_constraint); } - _FORCE_INLINE_ void remove_constraint(Constraint3DSW *p_constraint) { constraints.erase(p_constraint); } - _FORCE_INLINE_ const Set<Constraint3DSW *> &get_constraints() const { return constraints; } + _FORCE_INLINE_ void add_constraint(GodotConstraint3D *p_constraint) { constraints.insert(p_constraint); } + _FORCE_INLINE_ void remove_constraint(GodotConstraint3D *p_constraint) { constraints.erase(p_constraint); } + _FORCE_INLINE_ const Set<GodotConstraint3D *> &get_constraints() const { return constraints; } _FORCE_INLINE_ void clear_constraints() { constraints.clear(); } _FORCE_INLINE_ void add_exception(const RID &p_exception) { exceptions.insert(p_exception); } @@ -138,7 +134,7 @@ public: _FORCE_INLINE_ uint64_t get_island_step() const { return island_step; } _FORCE_INLINE_ void set_island_step(uint64_t p_step) { island_step = p_step; } - _FORCE_INLINE_ void add_area(Area3DSW *p_area) { + _FORCE_INLINE_ void add_area(GodotArea3D *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { areas.write[index].refCount += 1; @@ -147,19 +143,19 @@ public: } } - _FORCE_INLINE_ void remove_area(Area3DSW *p_area) { + _FORCE_INLINE_ void remove_area(GodotArea3D *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { areas.write[index].refCount -= 1; if (areas[index].refCount < 1) { - areas.remove(index); + areas.remove_at(index); } } } - virtual void set_space(Space3DSW *p_space); + virtual void set_space(GodotSpace3D *p_space); - void set_mesh(const Ref<Mesh> &p_mesh); + void set_mesh(RID p_mesh); void update_rendering_server(RenderingServerHandler *p_rendering_server_handler); @@ -233,7 +229,7 @@ private: void add_velocity(const Vector3 &p_velocity); - void apply_forces(bool p_has_wind_forces); + void apply_forces(const LocalVector<GodotArea3D *> &p_wind_areas); bool create_from_trimesh(const Vector<int> &p_indices, const Vector<Vector3> &p_vertices); void generate_bending_constraints(int p_distance); @@ -252,29 +248,29 @@ private: void destroy(); }; -class SoftBodyShape3DSW : public Shape3DSW { - SoftBody3DSW *soft_body = nullptr; +class GodotSoftBodyShape3D : public GodotShape3D { + GodotSoftBody3D *soft_body = nullptr; public: - SoftBody3DSW *get_soft_body() const { return soft_body; } + GodotSoftBody3D *get_soft_body() const { return soft_body; } - virtual PhysicsServer3D::ShapeType get_type() const { return PhysicsServer3D::SHAPE_SOFT_BODY; } - virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const { r_min = r_max = 0.0; } - virtual Vector3 get_support(const Vector3 &p_normal) const { return Vector3(); } - virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const { r_amount = 0; } + virtual PhysicsServer3D::ShapeType get_type() const override { return PhysicsServer3D::SHAPE_SOFT_BODY; } + virtual void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const override { r_min = r_max = 0.0; } + virtual Vector3 get_support(const Vector3 &p_normal) const override { return Vector3(); } + virtual void get_supports(const Vector3 &p_normal, int p_max, Vector3 *r_supports, int &r_amount, FeatureType &r_type) const override { r_amount = 0; } - virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal) const; - virtual bool intersect_point(const Vector3 &p_point) const; - virtual Vector3 get_closest_point_to(const Vector3 &p_point) const; - virtual Vector3 get_moment_of_inertia(real_t p_mass) const { return Vector3(); } + virtual bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_result, Vector3 &r_normal, bool p_hit_back_faces) const override; + virtual bool intersect_point(const Vector3 &p_point) const override; + virtual Vector3 get_closest_point_to(const Vector3 &p_point) const override; + virtual Vector3 get_moment_of_inertia(real_t p_mass) const override { return Vector3(); } - virtual void set_data(const Variant &p_data) {} - virtual Variant get_data() const { return Variant(); } + virtual void set_data(const Variant &p_data) override {} + virtual Variant get_data() const override { return Variant(); } void update_bounds(); - SoftBodyShape3DSW(SoftBody3DSW *p_soft_body); - ~SoftBodyShape3DSW() {} + GodotSoftBodyShape3D(GodotSoftBody3D *p_soft_body); + ~GodotSoftBodyShape3D() {} }; -#endif // SOFT_BODY_3D_SW_H +#endif // GODOT_SOFT_BODY_3D_H diff --git a/servers/physics_3d/space_3d_sw.cpp b/servers/physics_3d/godot_space_3d.cpp index 37dee436df..f503273c88 100644 --- a/servers/physics_3d/space_3d_sw.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* space_3d_sw.cpp */ +/* godot_space_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,35 +28,38 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "space_3d_sw.h" +#include "godot_space_3d.h" + +#include "godot_collision_solver_3d.h" +#include "godot_physics_server_3d.h" -#include "collision_solver_3d_sw.h" #include "core/config/project_settings.h" -#include "physics_server_3d_sw.h" -_FORCE_INLINE_ static bool _can_collide_with(CollisionObject3DSW *p_object, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +#define TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR 0.05 + +_FORCE_INLINE_ static bool _can_collide_with(GodotCollisionObject3D *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)) { return false; } - if (p_object->get_type() == CollisionObject3DSW::TYPE_AREA && !p_collide_with_areas) { + if (p_object->get_type() == GodotCollisionObject3D::TYPE_AREA && !p_collide_with_areas) { return false; } - if (p_object->get_type() == CollisionObject3DSW::TYPE_BODY && !p_collide_with_bodies) { + if (p_object->get_type() == GodotCollisionObject3D::TYPE_BODY && !p_collide_with_bodies) { return false; } - if (p_object->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY && !p_collide_with_bodies) { + if (p_object->get_type() == GodotCollisionObject3D::TYPE_SOFT_BODY && !p_collide_with_bodies) { return false; } return true; } -int PhysicsDirectSpaceState3DSW::intersect_point(const Vector3 &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) { +int GodotPhysicsDirectSpaceState3D::intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) { ERR_FAIL_COND_V(space->locked, false); - int amount = space->broadphase->cull_point(p_point, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_point(p_parameters.position, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); int cc = 0; //Transform3D ai = p_xform.affine_inverse(); @@ -66,23 +69,23 @@ int PhysicsDirectSpaceState3DSW::intersect_point(const Vector3 &p_point, ShapeRe break; } - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } //area can't be picked by ray (default) - if (p_exclude.has(space->intersection_query_results[i]->get_self())) { + if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) { continue; } - const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject3D *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; Transform3D inv_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); inv_xform.affine_invert(); - if (!col_obj->get_shape(shape_idx)->intersect_point(inv_xform.xform(p_point))) { + if (!col_obj->get_shape(shape_idx)->intersect_point(inv_xform.xform(p_parameters.position))) { continue; } @@ -101,39 +104,39 @@ int PhysicsDirectSpaceState3DSW::intersect_point(const Vector3 &p_point, ShapeRe return cc; } -bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vector3 &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, bool p_pick_ray) { +bool GodotPhysicsDirectSpaceState3D::intersect_ray(const RayParameters &p_parameters, RayResult &r_result) { ERR_FAIL_COND_V(space->locked, false); Vector3 begin, end; Vector3 normal; - begin = p_from; - end = p_to; + begin = p_parameters.from; + end = p_parameters.to; normal = (end - begin).normalized(); - int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_segment(begin, end, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); //todo, create another array that references results, compute AABBs and check closest point to ray origin, sort, and stop evaluating results when beyond first collision bool collided = false; Vector3 res_point, res_normal; int res_shape; - const CollisionObject3DSW *res_obj; + const GodotCollisionObject3D *res_obj; real_t min_d = 1e10; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - if (p_pick_ray && !(space->intersection_query_results[i]->is_ray_pickable())) { + if (p_parameters.pick_ray && !(space->intersection_query_results[i]->is_ray_pickable())) { continue; } - if (p_exclude.has(space->intersection_query_results[i]->get_self())) { + if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) { continue; } - const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject3D *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; Transform3D inv_xform = col_obj->get_shape_inv_transform(shape_idx) * col_obj->get_inv_transform(); @@ -141,11 +144,27 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec Vector3 local_from = inv_xform.xform(begin); Vector3 local_to = inv_xform.xform(end); - const Shape3DSW *shape = col_obj->get_shape(shape_idx); + const GodotShape3D *shape = col_obj->get_shape(shape_idx); Vector3 shape_point, shape_normal; - if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal)) { + if (shape->intersect_point(local_from)) { + if (p_parameters.hit_from_inside) { + // Hit shape at starting point. + min_d = 0; + res_point = local_from; + res_normal = Vector3(); + res_shape = shape_idx; + res_obj = col_obj; + collided = true; + break; + } else { + // Ignore shape when starting inside. + continue; + } + } + + if (shape->intersect_segment(local_from, local_to, shape_point, shape_normal, p_parameters.hit_back_faces)) { Transform3D xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); shape_point = xform.xform(shape_point); @@ -180,17 +199,17 @@ bool PhysicsDirectSpaceState3DSW::intersect_ray(const Vector3 &p_from, const Vec return true; } -int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Transform3D &p_xform, real_t p_margin, 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) { +int GodotPhysicsDirectSpaceState3D::intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) { if (p_result_max <= 0) { return 0; } - Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); + GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, 0); - AABB aabb = p_xform.xform(shape->get_aabb()); + AABB aabb = p_parameters.transform.xform(shape->get_aabb()); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); int cc = 0; @@ -201,20 +220,20 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans break; } - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } //area can't be picked by ray (default) - if (p_exclude.has(space->intersection_query_results[i]->get_self())) { + if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) { continue; } - const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject3D *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; - if (!CollisionSolver3DSW::solve_static(shape, p_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), nullptr, nullptr, nullptr, p_margin, 0)) { + if (!GodotCollisionSolver3D::solve_static(shape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), nullptr, nullptr, nullptr, p_parameters.margin, 0)) { continue; } @@ -235,40 +254,40 @@ int PhysicsDirectSpaceState3DSW::intersect_shape(const RID &p_shape, const Trans return cc; } -bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &p_motion, real_t p_margin, real_t &p_closest_safe, real_t &p_closest_unsafe, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas, ShapeRestInfo *r_info) { - Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); +bool GodotPhysicsDirectSpaceState3D::cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe, ShapeRestInfo *r_info) { + GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, false); - AABB aabb = p_xform.xform(shape->get_aabb()); - aabb = aabb.merge(AABB(aabb.position + p_motion, aabb.size)); //motion - aabb = aabb.grow(p_margin); + AABB aabb = p_parameters.transform.xform(shape->get_aabb()); + aabb = aabb.merge(AABB(aabb.position + p_parameters.motion, aabb.size)); //motion + aabb = aabb.grow(p_parameters.margin); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); real_t best_safe = 1; real_t best_unsafe = 1; - Transform3D xform_inv = p_xform.affine_inverse(); - MotionShape3DSW mshape; + Transform3D xform_inv = p_parameters.transform.affine_inverse(); + GodotMotionShape3D mshape; mshape.shape = shape; - mshape.motion = xform_inv.basis.xform(p_motion); + mshape.motion = xform_inv.basis.xform(p_parameters.motion); bool best_first = true; - Vector3 motion_normal = p_motion.normalized(); + Vector3 motion_normal = p_parameters.motion.normalized(); Vector3 closest_A, closest_B; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - if (p_exclude.has(space->intersection_query_results[i]->get_self())) { + if (p_parameters.exclude.has(space->intersection_query_results[i]->get_self())) { continue; //ignore excluded } - const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject3D *col_obj = space->intersection_query_results[i]; int shape_idx = space->intersection_query_subindex_results[i]; Vector3 point_A, point_B; @@ -276,14 +295,14 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor Transform3D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? - if (CollisionSolver3DSW::solve_distance(&mshape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) { + if (GodotCollisionSolver3D::solve_distance(&mshape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) { continue; } //test initial overlap, ignore objects it's inside of. sep_axis = motion_normal; - if (!CollisionSolver3DSW::solve_distance(shape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) { + if (!GodotCollisionSolver3D::solve_distance(shape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, aabb, &sep_axis)) { continue; } @@ -294,11 +313,11 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor for (int j = 0; j < 8; j++) { //steps should be customizable.. real_t fraction = low + (hi - low) * fraction_coeff; - mshape.motion = xform_inv.basis.xform(p_motion * fraction); + mshape.motion = xform_inv.basis.xform(p_parameters.motion * fraction); Vector3 lA, lB; Vector3 sep = motion_normal; //important optimization for this to work fast enough - bool collided = !CollisionSolver3DSW::solve_distance(&mshape, p_xform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, aabb, &sep); + bool collided = !GodotCollisionSolver3D::solve_distance(&mshape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, aabb, &sep); if (collided) { hi = fraction; @@ -340,8 +359,8 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor r_info->point = closest_B; r_info->normal = (closest_A - closest_B).normalized(); best_first = false; - if (col_obj->get_type() == CollisionObject3DSW::TYPE_BODY) { - const Body3DSW *body = static_cast<const Body3DSW *>(col_obj); + if (col_obj->get_type() == GodotCollisionObject3D::TYPE_BODY) { + const GodotBody3D *body = static_cast<const GodotBody3D *>(col_obj); Vector3 rel_vec = closest_B - (body->get_transform().origin + body->get_center_of_mass()); r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec); } @@ -354,44 +373,44 @@ bool PhysicsDirectSpaceState3DSW::cast_motion(const RID &p_shape, const Transfor return true; } -bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, const Set<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { +bool GodotPhysicsDirectSpaceState3D::collide_shape(const ShapeParameters &p_parameters, Vector3 *r_results, int p_result_max, int &r_result_count) { if (p_result_max <= 0) { return false; } - Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); + GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, 0); - AABB aabb = p_shape_xform.xform(shape->get_aabb()); - aabb = aabb.grow(p_margin); + AABB aabb = p_parameters.transform.xform(shape->get_aabb()); + aabb = aabb.grow(p_parameters.margin); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); bool collided = false; r_result_count = 0; - PhysicsServer3DSW::CollCbkData cbk; + GodotPhysicsServer3D::CollCbkData cbk; cbk.max = p_result_max; cbk.amount = 0; cbk.ptr = r_results; - CollisionSolver3DSW::CallbackResult cbkres = PhysicsServer3DSW::_shape_col_cbk; + GodotCollisionSolver3D::CallbackResult cbkres = GodotPhysicsServer3D::_shape_col_cbk; - PhysicsServer3DSW::CollCbkData *cbkptr = &cbk; + GodotPhysicsServer3D::CollCbkData *cbkptr = &cbk; for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject3D *col_obj = space->intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + if (p_parameters.exclude.has(col_obj->get_self())) { continue; } int shape_idx = space->intersection_query_subindex_results[i]; - if (CollisionSolver3DSW::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) { + if (GodotCollisionSolver3D::solve_static(shape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_parameters.margin)) { collided = true; } } @@ -401,17 +420,27 @@ bool PhysicsDirectSpaceState3DSW::collide_shape(RID p_shape, const Transform3D & return collided; } +struct _RestResultData { + const GodotCollisionObject3D *object = nullptr; + int local_shape = 0; + int shape = 0; + Vector3 contact; + Vector3 normal; + real_t len = 0.0; +}; + struct _RestCallbackData { - const CollisionObject3DSW *object; - const CollisionObject3DSW *best_object; - int local_shape; - int best_local_shape; - int shape; - int best_shape; - Vector3 best_contact; - Vector3 best_normal; - real_t best_len; - real_t min_allowed_depth; + const GodotCollisionObject3D *object = nullptr; + int local_shape = 0; + int shape = 0; + + real_t min_allowed_depth = 0.0; + + _RestResultData best_result; + + int max_results = 0; + int result_count = 0; + _RestResultData *other_results = nullptr; }; static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { @@ -422,41 +451,82 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect if (len < rd->min_allowed_depth) { return; } - if (len <= rd->best_len) { + + bool is_best_result = (len > rd->best_result.len); + + if (rd->other_results && rd->result_count > 0) { + // Consider as new result by default. + int prev_result_count = rd->result_count++; + + int result_index = 0; + real_t tested_len = is_best_result ? rd->best_result.len : len; + for (; result_index < prev_result_count - 1; ++result_index) { + if (tested_len > rd->other_results[result_index].len) { + // Re-using a previous result. + rd->result_count--; + break; + } + } + + if (result_index < rd->max_results - 1) { + _RestResultData &result = rd->other_results[result_index]; + + if (is_best_result) { + // Keep the previous best result as separate result. + result = rd->best_result; + } else { + // Keep this result as separate result. + result.len = len; + result.contact = p_point_B; + result.normal = contact_rel / len; + result.object = rd->object; + result.shape = rd->shape; + result.local_shape = rd->local_shape; + } + } else { + // Discarding this result. + rd->result_count--; + } + } else if (is_best_result) { + rd->result_count = 1; + } + + if (!is_best_result) { return; } - rd->best_len = len; - rd->best_contact = 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; + rd->best_result.len = len; + rd->best_result.contact = p_point_B; + rd->best_result.normal = contact_rel / len; + rd->best_result.object = rd->object; + rd->best_result.shape = rd->shape; + rd->best_result.local_shape = rd->local_shape; } -bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_shape_xform, 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) { - Shape3DSW *shape = PhysicsServer3DSW::singletonsw->shape_owner.getornull(p_shape); +bool GodotPhysicsDirectSpaceState3D::rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) { + GodotShape3D *shape = GodotPhysicsServer3D::godot_singleton->shape_owner.get_or_null(p_parameters.shape_rid); ERR_FAIL_COND_V(!shape, 0); - AABB aabb = p_shape_xform.xform(shape->get_aabb()); - aabb = aabb.grow(p_margin); + AABB aabb = p_parameters.transform.xform(shape->get_aabb()); + aabb = aabb.grow(p_parameters.margin); - int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, Space3DSW::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); + int amount = space->broadphase->cull_aabb(aabb, space->intersection_query_results, GodotSpace3D::INTERSECTION_QUERY_MAX, space->intersection_query_subindex_results); _RestCallbackData rcd; - rcd.best_len = 0; - rcd.best_object = nullptr; - rcd.best_shape = 0; - rcd.min_allowed_depth = space->test_motion_min_contact_depth; + + // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. + real_t motion_length = p_parameters.motion.length(); + real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; + rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); for (int i = 0; i < amount; i++) { - if (!_can_collide_with(space->intersection_query_results[i], p_collision_mask, p_collide_with_bodies, p_collide_with_areas)) { + if (!_can_collide_with(space->intersection_query_results[i], p_parameters.collision_mask, p_parameters.collide_with_bodies, p_parameters.collide_with_areas)) { continue; } - const CollisionObject3DSW *col_obj = space->intersection_query_results[i]; + const GodotCollisionObject3D *col_obj = space->intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + if (p_parameters.exclude.has(col_obj->get_self())) { continue; } @@ -464,24 +534,24 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_sh rcd.object = col_obj; rcd.shape = shape_idx; - bool sc = CollisionSolver3DSW::solve_static(shape, p_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin); + bool sc = GodotCollisionSolver3D::solve_static(shape, p_parameters.transform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_parameters.margin); if (!sc) { continue; } } - if (rcd.best_len == 0 || !rcd.best_object) { + if (rcd.best_result.len == 0 || !rcd.best_result.object) { return false; } - r_info->collider_id = rcd.best_object->get_instance_id(); - r_info->shape = rcd.best_shape; - r_info->normal = rcd.best_normal; - r_info->point = rcd.best_contact; - r_info->rid = rcd.best_object->get_self(); - if (rcd.best_object->get_type() == CollisionObject3DSW::TYPE_BODY) { - const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object); - Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass()); + r_info->collider_id = rcd.best_result.object->get_instance_id(); + r_info->shape = rcd.best_result.shape; + r_info->normal = rcd.best_result.normal; + r_info->point = rcd.best_result.contact; + r_info->rid = rcd.best_result.object->get_self(); + if (rcd.best_result.object->get_type() == GodotCollisionObject3D::TYPE_BODY) { + const GodotBody3D *body = static_cast<const GodotBody3D *>(rcd.best_result.object); + Vector3 rel_vec = rcd.best_result.contact - (body->get_transform().origin + body->get_center_of_mass()); r_info->linear_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec); } else { @@ -491,10 +561,10 @@ bool PhysicsDirectSpaceState3DSW::rest_info(RID p_shape, const Transform3D &p_sh return true; } -Vector3 PhysicsDirectSpaceState3DSW::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const { - CollisionObject3DSW *obj = PhysicsServer3DSW::singletonsw->area_owner.getornull(p_object); +Vector3 GodotPhysicsDirectSpaceState3D::get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const { + GodotCollisionObject3D *obj = GodotPhysicsServer3D::godot_singleton->area_owner.get_or_null(p_object); if (!obj) { - obj = PhysicsServer3DSW::singletonsw->body_owner.getornull(p_object); + obj = GodotPhysicsServer3D::godot_singleton->body_owner.get_or_null(p_object); } ERR_FAIL_COND_V(!obj, Vector3()); @@ -511,7 +581,7 @@ Vector3 PhysicsDirectSpaceState3DSW::get_closest_point_to_object_volume(RID p_ob } Transform3D shape_xform = obj->get_transform() * obj->get_shape_transform(i); - Shape3DSW *shape = obj->get_shape(i); + GodotShape3D *shape = obj->get_shape(i); Vector3 point = shape->get_closest_point_to(shape_xform.affine_inverse().xform(p_point)); point = shape_xform.xform(point); @@ -531,13 +601,13 @@ Vector3 PhysicsDirectSpaceState3DSW::get_closest_point_to_object_volume(RID p_ob } } -PhysicsDirectSpaceState3DSW::PhysicsDirectSpaceState3DSW() { +GodotPhysicsDirectSpaceState3D::GodotPhysicsDirectSpaceState3D() { space = nullptr; } //////////////////////////////////////////////////////////////////////////////////////////////////////////// -int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) { +int GodotSpace3D::_cull_aabb_for_body(GodotBody3D *p_body, const AABB &p_aabb) { int amount = broadphase->cull_aabb(p_aabb, intersection_query_results, INTERSECTION_QUERY_MAX, intersection_query_subindex_results); for (int i = 0; i < amount; i++) { @@ -545,13 +615,13 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) { if (intersection_query_results[i] == p_body) { keep = false; - } else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_AREA) { + } else if (intersection_query_results[i]->get_type() == GodotCollisionObject3D::TYPE_AREA) { keep = false; - } else if (intersection_query_results[i]->get_type() == CollisionObject3DSW::TYPE_SOFT_BODY) { + } else if (intersection_query_results[i]->get_type() == GodotCollisionObject3D::TYPE_SOFT_BODY) { keep = false; - } else if (!p_body->collides_with(static_cast<Body3DSW *>(intersection_query_results[i]))) { + } else if (!p_body->collides_with(static_cast<GodotBody3D *>(intersection_query_results[i]))) { keep = false; - } else if (static_cast<Body3DSW *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) { + } else if (static_cast<GodotBody3D *>(intersection_query_results[i])->has_exception(p_body->get_self()) || p_body->has_exception(intersection_query_results[i]->get_self())) { keep = false; } @@ -569,7 +639,7 @@ int Space3DSW::_cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb) { return amount; } -bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_collide_separation_ray, const Set<RID> &p_exclude) { +bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult *r_result) { //give me back regular physics engine logic //this is madness //and most people using this function will think @@ -577,10 +647,12 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co //this took about a week to get right.. //but is it right? who knows at this point.. + ERR_FAIL_INDEX_V(p_parameters.max_collisions, PhysicsServer3D::MotionResult::MAX_COLLISIONS, false); + if (r_result) { - r_result->collider_id = ObjectID(); - r_result->collider_shape = 0; + *r_result = PhysicsServer3D::MotionResult(); } + AABB body_aabb; bool shapes_found = false; @@ -599,21 +671,22 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co if (!shapes_found) { if (r_result) { - *r_result = PhysicsServer3D::MotionResult(); - r_result->travel = p_motion; + r_result->travel = p_parameters.motion; } return false; } // Undo the currently transform the physics server is aware of and apply the provided one - body_aabb = p_from.xform(p_body->get_inv_transform().xform(body_aabb)); - body_aabb = body_aabb.grow(p_margin); + body_aabb = p_parameters.from.xform(p_body->get_inv_transform().xform(body_aabb)); + body_aabb = body_aabb.grow(p_parameters.margin); + + real_t min_contact_depth = p_parameters.margin * TEST_MOTION_MIN_CONTACT_DEPTH_FACTOR; - real_t motion_length = p_motion.length(); - Vector3 motion_normal = p_motion / motion_length; + real_t motion_length = p_parameters.motion.length(); + Vector3 motion_normal = p_parameters.motion / motion_length; - Transform3D body_transform = p_from; + Transform3D body_transform = p_parameters.from; bool recovered = false; @@ -625,13 +698,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co Vector3 sr[max_results * 2]; do { - PhysicsServer3DSW::CollCbkData cbk; + GodotPhysicsServer3D::CollCbkData cbk; cbk.max = max_results; cbk.amount = 0; cbk.ptr = sr; - PhysicsServer3DSW::CollCbkData *cbkptr = &cbk; - CollisionSolver3DSW::CallbackResult cbkres = PhysicsServer3DSW::_shape_col_cbk; + GodotPhysicsServer3D::CollCbkData *cbkptr = &cbk; + GodotCollisionSolver3D::CallbackResult cbkres = GodotPhysicsServer3D::_shape_col_cbk; bool collided = false; @@ -643,17 +716,20 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co } Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j); - Shape3DSW *body_shape = p_body->get_shape(j); + GodotShape3D *body_shape = p_body->get_shape(j); for (int i = 0; i < amount; i++) { - const CollisionObject3DSW *col_obj = intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + const GodotCollisionObject3D *col_obj = intersection_query_results[i]; + if (p_parameters.exclude_bodies.has(col_obj->get_self())) { + continue; + } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { continue; } int shape_idx = intersection_query_subindex_results[i]; - if (CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_margin)) { + if (GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), cbkres, cbkptr, nullptr, p_parameters.margin)) { collided = cbk.amount > 0; } } @@ -663,8 +739,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co break; } - Vector3 recover_motion; + recovered = true; + Vector3 recover_motion; for (int i = 0; i < cbk.amount; i++) { Vector3 a = sr[i * 2 + 0]; Vector3 b = sr[i * 2 + 1]; @@ -675,9 +752,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co // Compute depth on recovered motion. real_t depth = n.dot(a + recover_motion) - d; - if (depth > 0.0) { + if (depth > min_contact_depth + CMP_EPSILON) { // Only recover if there is penetration. - recover_motion -= n * depth * 0.4; + recover_motion -= n * (depth - min_contact_depth) * 0.4; } } @@ -686,8 +763,6 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co break; } - recovered = true; - body_transform.origin += recover_motion; body_aabb.position += recover_motion; @@ -704,7 +779,7 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co // STEP 2 ATTEMPT MOTION AABB motion_aabb = body_aabb; - motion_aabb.position += p_motion; + motion_aabb.position += p_parameters.motion; motion_aabb = motion_aabb.merge(body_aabb); int amount = _cull_aabb_for_body(p_body, motion_aabb); @@ -714,13 +789,13 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co continue; } - Shape3DSW *body_shape = p_body->get_shape(j); + GodotShape3D *body_shape = p_body->get_shape(j); // Colliding separation rays allows to properly snap to the ground, // otherwise it's not needed in regular motion. - if (!p_collide_separation_ray && (body_shape->get_type() == PhysicsServer3D::SHAPE_SEPARATION_RAY)) { + if (!p_parameters.collide_separation_ray && (body_shape->get_type() == PhysicsServer3D::SHAPE_SEPARATION_RAY)) { // When slide on slope is on, separation ray shape acts like a regular shape. - if (!static_cast<SeparationRayShape3DSW *>(body_shape)->get_slide_on_slope()) { + if (!static_cast<GodotSeparationRayShape3D *>(body_shape)->get_slide_on_slope()) { continue; } } @@ -728,9 +803,9 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co Transform3D body_shape_xform = body_transform * p_body->get_shape_transform(j); Transform3D body_shape_xform_inv = body_shape_xform.affine_inverse(); - MotionShape3DSW mshape; + GodotMotionShape3D mshape; mshape.shape = body_shape; - mshape.motion = body_shape_xform_inv.basis.xform(p_motion); + mshape.motion = body_shape_xform_inv.basis.xform(p_parameters.motion); bool stuck = false; @@ -738,8 +813,11 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co real_t best_unsafe = 1; for (int i = 0; i < amount; i++) { - const CollisionObject3DSW *col_obj = intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + const GodotCollisionObject3D *col_obj = intersection_query_results[i]; + if (p_parameters.exclude_bodies.has(col_obj->get_self())) { + continue; + } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { continue; } @@ -751,12 +829,12 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co Transform3D col_obj_xform = col_obj->get_transform() * col_obj->get_shape_transform(shape_idx); //test initial overlap, does it collide if going all the way? - if (CollisionSolver3DSW::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) { + if (GodotCollisionSolver3D::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) { continue; } sep_axis = motion_normal; - if (!CollisionSolver3DSW::solve_distance(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) { + if (!GodotCollisionSolver3D::solve_distance(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, point_A, point_B, motion_aabb, &sep_axis)) { stuck = true; break; } @@ -768,11 +846,11 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co for (int k = 0; k < 8; k++) { //steps should be customizable.. real_t fraction = low + (hi - low) * fraction_coeff; - mshape.motion = body_shape_xform_inv.basis.xform(p_motion * fraction); + mshape.motion = body_shape_xform_inv.basis.xform(p_parameters.motion * fraction); Vector3 lA, lB; Vector3 sep = motion_normal; //important optimization for this to work fast enough - bool collided = !CollisionSolver3DSW::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, motion_aabb, &sep); + bool collided = !GodotCollisionSolver3D::solve_distance(&mshape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj_xform, lA, lB, motion_aabb, &sep); if (collided) { hi = fraction; @@ -830,15 +908,18 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co //it collided, let's get the rest info in unsafe advance Transform3D ugt = body_transform; - ugt.origin += p_motion * unsafe; + ugt.origin += p_parameters.motion * unsafe; + + _RestResultData results[PhysicsServer3D::MotionResult::MAX_COLLISIONS]; _RestCallbackData rcd; - rcd.best_len = 0; - rcd.best_object = nullptr; - rcd.best_shape = 0; + if (p_parameters.max_collisions > 1) { + rcd.max_results = p_parameters.max_collisions; + rcd.other_results = results; + } // Allowed depth can't be lower than motion length, in order to handle contacts at low speed. - rcd.min_allowed_depth = MIN(motion_length, test_motion_min_contact_depth); + rcd.min_allowed_depth = MIN(motion_length, min_contact_depth); int from_shape = best_shape != -1 ? best_shape : 0; int to_shape = best_shape != -1 ? best_shape + 1 : p_body->get_shape_count(); @@ -849,49 +930,61 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co } Transform3D body_shape_xform = ugt * p_body->get_shape_transform(j); - Shape3DSW *body_shape = p_body->get_shape(j); + GodotShape3D *body_shape = p_body->get_shape(j); - body_aabb.position += p_motion * unsafe; + body_aabb.position += p_parameters.motion * unsafe; int amount = _cull_aabb_for_body(p_body, body_aabb); for (int i = 0; i < amount; i++) { - const CollisionObject3DSW *col_obj = intersection_query_results[i]; - if (p_exclude.has(col_obj->get_self())) { + const GodotCollisionObject3D *col_obj = intersection_query_results[i]; + if (p_parameters.exclude_bodies.has(col_obj->get_self())) { continue; } + if (p_parameters.exclude_objects.has(col_obj->get_instance_id())) { + continue; + } + int shape_idx = intersection_query_subindex_results[i]; rcd.object = col_obj; rcd.shape = shape_idx; - bool sc = CollisionSolver3DSW::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_margin); + bool sc = GodotCollisionSolver3D::solve_static(body_shape, body_shape_xform, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), _rest_cbk_result, &rcd, nullptr, p_parameters.margin); if (!sc) { continue; } } } - if (rcd.best_len != 0) { + if (rcd.result_count > 0) { if (r_result) { - 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 = rcd.best_local_shape; - r_result->collision_normal = rcd.best_normal; - r_result->collision_point = rcd.best_contact; - r_result->collision_depth = rcd.best_len; - r_result->collision_safe_fraction = safe; - r_result->collision_unsafe_fraction = unsafe; - //r_result->collider_metadata = rcd.best_object->get_shape_metadata(rcd.best_shape); + for (int collision_index = 0; collision_index < rcd.result_count; ++collision_index) { + const _RestResultData &result = (collision_index > 0) ? rcd.other_results[collision_index - 1] : rcd.best_result; + + PhysicsServer3D::MotionCollision &collision = r_result->collisions[collision_index]; + + collision.collider = result.object->get_self(); + collision.collider_id = result.object->get_instance_id(); + collision.collider_shape = result.shape; + collision.local_shape = result.local_shape; + collision.normal = result.normal; + collision.position = result.contact; + collision.depth = result.len; + + const GodotBody3D *body = static_cast<const GodotBody3D *>(result.object); - const Body3DSW *body = static_cast<const Body3DSW *>(rcd.best_object); + Vector3 rel_vec = result.contact - (body->get_transform().origin + body->get_center_of_mass()); + collision.collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec); + } + + r_result->travel = safe * p_parameters.motion; + r_result->remainder = p_parameters.motion - safe * p_parameters.motion; + r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin()); - Vector3 rel_vec = rcd.best_contact - (body->get_transform().origin + body->get_center_of_mass()); - r_result->collider_velocity = body->get_linear_velocity() + (body->get_angular_velocity()).cross(rel_vec); + r_result->collision_safe_fraction = safe; + r_result->collision_unsafe_fraction = unsafe; - r_result->travel = safe * p_motion; - r_result->remainder = p_motion - safe * p_motion; - r_result->travel += (body_transform.get_origin() - p_from.get_origin()); + r_result->collision_count = rcd.result_count; } collided = true; @@ -899,52 +992,55 @@ bool Space3DSW::test_body_motion(Body3DSW *p_body, const Transform3D &p_from, co } if (!collided && r_result) { - r_result->travel = p_motion; + r_result->travel = p_parameters.motion; r_result->remainder = Vector3(); - r_result->travel += (body_transform.get_origin() - p_from.get_origin()); + r_result->travel += (body_transform.get_origin() - p_parameters.from.get_origin()); + + r_result->collision_safe_fraction = 1.0; + r_result->collision_unsafe_fraction = 1.0; } return collided; } -void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_self) { +void *GodotSpace3D::_broadphase_pair(GodotCollisionObject3D *A, int p_subindex_A, GodotCollisionObject3D *B, int p_subindex_B, void *p_self) { if (!A->interacts_with(B)) { return nullptr; } - CollisionObject3DSW::Type type_A = A->get_type(); - CollisionObject3DSW::Type type_B = B->get_type(); + GodotCollisionObject3D::Type type_A = A->get_type(); + GodotCollisionObject3D::Type type_B = B->get_type(); if (type_A > type_B) { SWAP(A, B); SWAP(p_subindex_A, p_subindex_B); SWAP(type_A, type_B); } - Space3DSW *self = (Space3DSW *)p_self; + GodotSpace3D *self = (GodotSpace3D *)p_self; self->collision_pairs++; - if (type_A == CollisionObject3DSW::TYPE_AREA) { - Area3DSW *area = static_cast<Area3DSW *>(A); - if (type_B == CollisionObject3DSW::TYPE_AREA) { - Area3DSW *area_b = static_cast<Area3DSW *>(B); - Area2Pair3DSW *area2_pair = memnew(Area2Pair3DSW(area_b, p_subindex_B, area, p_subindex_A)); + if (type_A == GodotCollisionObject3D::TYPE_AREA) { + GodotArea3D *area = static_cast<GodotArea3D *>(A); + if (type_B == GodotCollisionObject3D::TYPE_AREA) { + GodotArea3D *area_b = static_cast<GodotArea3D *>(B); + GodotArea2Pair3D *area2_pair = memnew(GodotArea2Pair3D(area_b, p_subindex_B, area, p_subindex_A)); return area2_pair; - } else if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) { - SoftBody3DSW *softbody = static_cast<SoftBody3DSW *>(B); - AreaSoftBodyPair3DSW *soft_area_pair = memnew(AreaSoftBodyPair3DSW(softbody, p_subindex_B, area, p_subindex_A)); + } else if (type_B == GodotCollisionObject3D::TYPE_SOFT_BODY) { + GodotSoftBody3D *softbody = static_cast<GodotSoftBody3D *>(B); + GodotAreaSoftBodyPair3D *soft_area_pair = memnew(GodotAreaSoftBodyPair3D(softbody, p_subindex_B, area, p_subindex_A)); return soft_area_pair; } else { - Body3DSW *body = static_cast<Body3DSW *>(B); - AreaPair3DSW *area_pair = memnew(AreaPair3DSW(body, p_subindex_B, area, p_subindex_A)); + GodotBody3D *body = static_cast<GodotBody3D *>(B); + GodotAreaPair3D *area_pair = memnew(GodotAreaPair3D(body, p_subindex_B, area, p_subindex_A)); return area_pair; } - } else if (type_A == CollisionObject3DSW::TYPE_BODY) { - if (type_B == CollisionObject3DSW::TYPE_SOFT_BODY) { - BodySoftBodyPair3DSW *soft_pair = memnew(BodySoftBodyPair3DSW((Body3DSW *)A, p_subindex_A, (SoftBody3DSW *)B)); + } else if (type_A == GodotCollisionObject3D::TYPE_BODY) { + if (type_B == GodotCollisionObject3D::TYPE_SOFT_BODY) { + GodotBodySoftBodyPair3D *soft_pair = memnew(GodotBodySoftBodyPair3D((GodotBody3D *)A, p_subindex_A, (GodotSoftBody3D *)B)); return soft_pair; } else { - BodyPair3DSW *b = memnew(BodyPair3DSW((Body3DSW *)A, p_subindex_A, (Body3DSW *)B, p_subindex_B)); + GodotBodyPair3D *b = memnew(GodotBodyPair3D((GodotBody3D *)A, p_subindex_A, (GodotBody3D *)B, p_subindex_B)); return b; } } else { @@ -954,122 +1050,122 @@ void *Space3DSW::_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, Coll return nullptr; } -void Space3DSW::_broadphase_unpair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_self) { +void GodotSpace3D::_broadphase_unpair(GodotCollisionObject3D *A, int p_subindex_A, GodotCollisionObject3D *B, int p_subindex_B, void *p_data, void *p_self) { if (!p_data) { return; } - Space3DSW *self = (Space3DSW *)p_self; + GodotSpace3D *self = (GodotSpace3D *)p_self; self->collision_pairs--; - Constraint3DSW *c = (Constraint3DSW *)p_data; + GodotConstraint3D *c = (GodotConstraint3D *)p_data; memdelete(c); } -const SelfList<Body3DSW>::List &Space3DSW::get_active_body_list() const { +const SelfList<GodotBody3D>::List &GodotSpace3D::get_active_body_list() const { return active_list; } -void Space3DSW::body_add_to_active_list(SelfList<Body3DSW> *p_body) { +void GodotSpace3D::body_add_to_active_list(SelfList<GodotBody3D> *p_body) { active_list.add(p_body); } -void Space3DSW::body_remove_from_active_list(SelfList<Body3DSW> *p_body) { +void GodotSpace3D::body_remove_from_active_list(SelfList<GodotBody3D> *p_body) { active_list.remove(p_body); } -void Space3DSW::body_add_to_inertia_update_list(SelfList<Body3DSW> *p_body) { - inertia_update_list.add(p_body); +void GodotSpace3D::body_add_to_mass_properties_update_list(SelfList<GodotBody3D> *p_body) { + mass_properties_update_list.add(p_body); } -void Space3DSW::body_remove_from_inertia_update_list(SelfList<Body3DSW> *p_body) { - inertia_update_list.remove(p_body); +void GodotSpace3D::body_remove_from_mass_properties_update_list(SelfList<GodotBody3D> *p_body) { + mass_properties_update_list.remove(p_body); } -BroadPhase3DSW *Space3DSW::get_broadphase() { +GodotBroadPhase3D *GodotSpace3D::get_broadphase() { return broadphase; } -void Space3DSW::add_object(CollisionObject3DSW *p_object) { +void GodotSpace3D::add_object(GodotCollisionObject3D *p_object) { ERR_FAIL_COND(objects.has(p_object)); objects.insert(p_object); } -void Space3DSW::remove_object(CollisionObject3DSW *p_object) { +void GodotSpace3D::remove_object(GodotCollisionObject3D *p_object) { ERR_FAIL_COND(!objects.has(p_object)); objects.erase(p_object); } -const Set<CollisionObject3DSW *> &Space3DSW::get_objects() const { +const Set<GodotCollisionObject3D *> &GodotSpace3D::get_objects() const { return objects; } -void Space3DSW::body_add_to_state_query_list(SelfList<Body3DSW> *p_body) { +void GodotSpace3D::body_add_to_state_query_list(SelfList<GodotBody3D> *p_body) { state_query_list.add(p_body); } -void Space3DSW::body_remove_from_state_query_list(SelfList<Body3DSW> *p_body) { +void GodotSpace3D::body_remove_from_state_query_list(SelfList<GodotBody3D> *p_body) { state_query_list.remove(p_body); } -void Space3DSW::area_add_to_monitor_query_list(SelfList<Area3DSW> *p_area) { +void GodotSpace3D::area_add_to_monitor_query_list(SelfList<GodotArea3D> *p_area) { monitor_query_list.add(p_area); } -void Space3DSW::area_remove_from_monitor_query_list(SelfList<Area3DSW> *p_area) { +void GodotSpace3D::area_remove_from_monitor_query_list(SelfList<GodotArea3D> *p_area) { monitor_query_list.remove(p_area); } -void Space3DSW::area_add_to_moved_list(SelfList<Area3DSW> *p_area) { +void GodotSpace3D::area_add_to_moved_list(SelfList<GodotArea3D> *p_area) { area_moved_list.add(p_area); } -void Space3DSW::area_remove_from_moved_list(SelfList<Area3DSW> *p_area) { +void GodotSpace3D::area_remove_from_moved_list(SelfList<GodotArea3D> *p_area) { area_moved_list.remove(p_area); } -const SelfList<Area3DSW>::List &Space3DSW::get_moved_area_list() const { +const SelfList<GodotArea3D>::List &GodotSpace3D::get_moved_area_list() const { return area_moved_list; } -const SelfList<SoftBody3DSW>::List &Space3DSW::get_active_soft_body_list() const { +const SelfList<GodotSoftBody3D>::List &GodotSpace3D::get_active_soft_body_list() const { return active_soft_body_list; } -void Space3DSW::soft_body_add_to_active_list(SelfList<SoftBody3DSW> *p_soft_body) { +void GodotSpace3D::soft_body_add_to_active_list(SelfList<GodotSoftBody3D> *p_soft_body) { active_soft_body_list.add(p_soft_body); } -void Space3DSW::soft_body_remove_from_active_list(SelfList<SoftBody3DSW> *p_soft_body) { +void GodotSpace3D::soft_body_remove_from_active_list(SelfList<GodotSoftBody3D> *p_soft_body) { active_soft_body_list.remove(p_soft_body); } -void Space3DSW::call_queries() { +void GodotSpace3D::call_queries() { while (state_query_list.first()) { - Body3DSW *b = state_query_list.first()->self(); + GodotBody3D *b = state_query_list.first()->self(); state_query_list.remove(state_query_list.first()); b->call_queries(); } while (monitor_query_list.first()) { - Area3DSW *a = monitor_query_list.first()->self(); + GodotArea3D *a = monitor_query_list.first()->self(); monitor_query_list.remove(monitor_query_list.first()); a->call_queries(); } } -void Space3DSW::setup() { +void GodotSpace3D::setup() { contact_debug_count = 0; - while (inertia_update_list.first()) { - inertia_update_list.first()->self()->update_inertias(); - inertia_update_list.remove(inertia_update_list.first()); + while (mass_properties_update_list.first()) { + mass_properties_update_list.first()->self()->update_mass_properties(); + mass_properties_update_list.remove(mass_properties_update_list.first()); } } -void Space3DSW::update() { +void GodotSpace3D::update() { broadphase->update(); } -void Space3DSW::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value) { +void GodotSpace3D::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_value) { switch (p_param) { case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: contact_recycle_radius = p_value; @@ -1095,13 +1191,10 @@ void Space3DSW::set_param(PhysicsServer3D::SpaceParameter p_param, real_t p_valu case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: constraint_bias = p_value; break; - case PhysicsServer3D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: - test_motion_min_contact_depth = p_value; - break; } } -real_t Space3DSW::get_param(PhysicsServer3D::SpaceParameter p_param) const { +real_t GodotSpace3D::get_param(PhysicsServer3D::SpaceParameter p_param) const { switch (p_param) { case PhysicsServer3D::SPACE_PARAM_CONTACT_RECYCLE_RADIUS: return contact_recycle_radius; @@ -1119,61 +1212,42 @@ real_t Space3DSW::get_param(PhysicsServer3D::SpaceParameter p_param) const { return body_angular_velocity_damp_ratio; case PhysicsServer3D::SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS: return constraint_bias; - case PhysicsServer3D::SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH: - return test_motion_min_contact_depth; } return 0; } -void Space3DSW::lock() { +void GodotSpace3D::lock() { locked = true; } -void Space3DSW::unlock() { +void GodotSpace3D::unlock() { locked = false; } -bool Space3DSW::is_locked() const { +bool GodotSpace3D::is_locked() const { return locked; } -PhysicsDirectSpaceState3DSW *Space3DSW::get_direct_state() { +GodotPhysicsDirectSpaceState3D *GodotSpace3D::get_direct_state() { return direct_access; } -Space3DSW::Space3DSW() { - collision_pairs = 0; - active_objects = 0; - island_count = 0; - contact_debug_count = 0; - - locked = false; - contact_recycle_radius = 0.01; - contact_max_separation = 0.05; - contact_max_allowed_penetration = 0.01; - test_motion_min_contact_depth = 0.00001; - - constraint_bias = 0.01; +GodotSpace3D::GodotSpace3D() { 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", Math::deg2rad(8.0)); 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::FLOAT, "physics/3d/time_before_sleep", PROPERTY_HINT_RANGE, "0,5,0.01,or_greater")); body_angular_velocity_damp_ratio = 10; - broadphase = BroadPhase3DSW::create_func(); + broadphase = GodotBroadPhase3D::create_func(); broadphase->set_pair_callback(_broadphase_pair, this); broadphase->set_unpair_callback(_broadphase_unpair, this); - area = nullptr; - direct_access = memnew(PhysicsDirectSpaceState3DSW); + direct_access = memnew(GodotPhysicsDirectSpaceState3D); direct_access->space = this; - - for (int i = 0; i < ELAPSED_TIME_MAX; i++) { - elapsed_time[i] = 0; - } } -Space3DSW::~Space3DSW() { +GodotSpace3D::~GodotSpace3D() { memdelete(broadphase); memdelete(direct_access); } diff --git a/servers/physics_3d/space_3d_sw.h b/servers/physics_3d/godot_space_3d.h index eff494a7bc..aa5e965751 100644 --- a/servers/physics_3d/space_3d_sw.h +++ b/servers/physics_3d/godot_space_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* space_3d_sw.h */ +/* godot_space_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,38 +28,39 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef SPACE_SW_H -#define SPACE_SW_H +#ifndef GODOT_SPACE_3D_H +#define GODOT_SPACE_3D_H + +#include "godot_area_3d.h" +#include "godot_area_pair_3d.h" +#include "godot_body_3d.h" +#include "godot_body_pair_3d.h" +#include "godot_broad_phase_3d.h" +#include "godot_collision_object_3d.h" +#include "godot_soft_body_3d.h" -#include "area_3d_sw.h" -#include "area_pair_3d_sw.h" -#include "body_3d_sw.h" -#include "body_pair_3d_sw.h" -#include "broad_phase_3d_sw.h" -#include "collision_object_3d_sw.h" #include "core/config/project_settings.h" #include "core/templates/hash_map.h" #include "core/typedefs.h" -#include "soft_body_3d_sw.h" -class PhysicsDirectSpaceState3DSW : public PhysicsDirectSpaceState3D { - GDCLASS(PhysicsDirectSpaceState3DSW, PhysicsDirectSpaceState3D); +class GodotPhysicsDirectSpaceState3D : public PhysicsDirectSpaceState3D { + GDCLASS(GodotPhysicsDirectSpaceState3D, PhysicsDirectSpaceState3D); public: - Space3DSW *space; - - virtual int intersect_point(const Vector3 &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) override; - virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &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, bool p_pick_ray = false) override; - virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, 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) override; - virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &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, ShapeRestInfo *r_info = nullptr) override; - virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, 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) override; - virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, 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) override; + GodotSpace3D *space; + + virtual int intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) override; + virtual bool intersect_ray(const RayParameters &p_parameters, RayResult &r_result) override; + virtual int intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) override; + virtual bool cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe, ShapeRestInfo *r_info = nullptr) override; + virtual bool collide_shape(const ShapeParameters &p_parameters, Vector3 *r_results, int p_result_max, int &r_result_count) override; + virtual bool rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) override; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const override; - PhysicsDirectSpaceState3DSW(); + GodotPhysicsDirectSpaceState3D(); }; -class Space3DSW { +class GodotSpace3D { public: enum ElapsedTime { ELAPSED_TIME_INTEGRATE_FORCES, @@ -72,37 +73,36 @@ public: }; private: - uint64_t elapsed_time[ELAPSED_TIME_MAX]; + uint64_t elapsed_time[ELAPSED_TIME_MAX] = {}; - PhysicsDirectSpaceState3DSW *direct_access; + GodotPhysicsDirectSpaceState3D *direct_access; RID self; - BroadPhase3DSW *broadphase; - SelfList<Body3DSW>::List active_list; - SelfList<Body3DSW>::List inertia_update_list; - SelfList<Body3DSW>::List state_query_list; - SelfList<Area3DSW>::List monitor_query_list; - SelfList<Area3DSW>::List area_moved_list; - SelfList<SoftBody3DSW>::List active_soft_body_list; + GodotBroadPhase3D *broadphase; + SelfList<GodotBody3D>::List active_list; + SelfList<GodotBody3D>::List mass_properties_update_list; + SelfList<GodotBody3D>::List state_query_list; + SelfList<GodotArea3D>::List monitor_query_list; + SelfList<GodotArea3D>::List area_moved_list; + SelfList<GodotSoftBody3D>::List active_soft_body_list; - static void *_broadphase_pair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_self); - static void _broadphase_unpair(CollisionObject3DSW *A, int p_subindex_A, CollisionObject3DSW *B, int p_subindex_B, void *p_data, void *p_self); + static void *_broadphase_pair(GodotCollisionObject3D *A, int p_subindex_A, GodotCollisionObject3D *B, int p_subindex_B, void *p_self); + static void _broadphase_unpair(GodotCollisionObject3D *A, int p_subindex_A, GodotCollisionObject3D *B, int p_subindex_B, void *p_data, void *p_self); - Set<CollisionObject3DSW *> objects; + Set<GodotCollisionObject3D *> objects; - Area3DSW *area; + GodotArea3D *area = nullptr; - real_t contact_recycle_radius; - real_t contact_max_separation; - real_t contact_max_allowed_penetration; - real_t constraint_bias; - real_t test_motion_min_contact_depth; + real_t contact_recycle_radius = 0.01; + real_t contact_max_separation = 0.05; + real_t contact_max_allowed_penetration = 0.01; + real_t constraint_bias = 0.01; enum { INTERSECTION_QUERY_MAX = 2048 }; - CollisionObject3DSW *intersection_query_results[INTERSECTION_QUERY_MAX]; + GodotCollisionObject3D *intersection_query_results[INTERSECTION_QUERY_MAX]; int intersection_query_subindex_results[INTERSECTION_QUERY_MAX]; real_t body_linear_velocity_sleep_threshold; @@ -110,54 +110,54 @@ private: real_t body_time_to_sleep; real_t body_angular_velocity_damp_ratio; - bool locked; + bool locked = false; real_t last_step = 0.001; - int island_count; - int active_objects; - int collision_pairs; + int island_count = 0; + int active_objects = 0; + int collision_pairs = 0; RID static_global_body; Vector<Vector3> contact_debug; - int contact_debug_count; + int contact_debug_count = 0; - friend class PhysicsDirectSpaceState3DSW; + friend class GodotPhysicsDirectSpaceState3D; - int _cull_aabb_for_body(Body3DSW *p_body, const AABB &p_aabb); + int _cull_aabb_for_body(GodotBody3D *p_body, const AABB &p_aabb); public: _FORCE_INLINE_ void set_self(const RID &p_self) { self = p_self; } _FORCE_INLINE_ RID get_self() const { return self; } - void set_default_area(Area3DSW *p_area) { area = p_area; } - Area3DSW *get_default_area() const { return area; } + void set_default_area(GodotArea3D *p_area) { area = p_area; } + GodotArea3D *get_default_area() const { return area; } - const SelfList<Body3DSW>::List &get_active_body_list() const; - void body_add_to_active_list(SelfList<Body3DSW> *p_body); - void body_remove_from_active_list(SelfList<Body3DSW> *p_body); - void body_add_to_inertia_update_list(SelfList<Body3DSW> *p_body); - void body_remove_from_inertia_update_list(SelfList<Body3DSW> *p_body); + const SelfList<GodotBody3D>::List &get_active_body_list() const; + void body_add_to_active_list(SelfList<GodotBody3D> *p_body); + void body_remove_from_active_list(SelfList<GodotBody3D> *p_body); + void body_add_to_mass_properties_update_list(SelfList<GodotBody3D> *p_body); + void body_remove_from_mass_properties_update_list(SelfList<GodotBody3D> *p_body); - void body_add_to_state_query_list(SelfList<Body3DSW> *p_body); - void body_remove_from_state_query_list(SelfList<Body3DSW> *p_body); + void body_add_to_state_query_list(SelfList<GodotBody3D> *p_body); + void body_remove_from_state_query_list(SelfList<GodotBody3D> *p_body); - void area_add_to_monitor_query_list(SelfList<Area3DSW> *p_area); - void area_remove_from_monitor_query_list(SelfList<Area3DSW> *p_area); - void area_add_to_moved_list(SelfList<Area3DSW> *p_area); - void area_remove_from_moved_list(SelfList<Area3DSW> *p_area); - const SelfList<Area3DSW>::List &get_moved_area_list() const; + void area_add_to_monitor_query_list(SelfList<GodotArea3D> *p_area); + void area_remove_from_monitor_query_list(SelfList<GodotArea3D> *p_area); + void area_add_to_moved_list(SelfList<GodotArea3D> *p_area); + void area_remove_from_moved_list(SelfList<GodotArea3D> *p_area); + const SelfList<GodotArea3D>::List &get_moved_area_list() const; - const SelfList<SoftBody3DSW>::List &get_active_soft_body_list() const; - void soft_body_add_to_active_list(SelfList<SoftBody3DSW> *p_soft_body); - void soft_body_remove_from_active_list(SelfList<SoftBody3DSW> *p_soft_body); + const SelfList<GodotSoftBody3D>::List &get_active_soft_body_list() const; + void soft_body_add_to_active_list(SelfList<GodotSoftBody3D> *p_soft_body); + void soft_body_remove_from_active_list(SelfList<GodotSoftBody3D> *p_soft_body); - BroadPhase3DSW *get_broadphase(); + GodotBroadPhase3D *get_broadphase(); - void add_object(CollisionObject3DSW *p_object); - void remove_object(CollisionObject3DSW *p_object); - const Set<CollisionObject3DSW *> &get_objects() const; + void add_object(GodotCollisionObject3D *p_object); + void remove_object(GodotCollisionObject3D *p_object); + const Set<GodotCollisionObject3D *> &get_objects() const; _FORCE_INLINE_ real_t get_contact_recycle_radius() const { return contact_recycle_radius; } _FORCE_INLINE_ real_t get_contact_max_separation() const { return contact_max_separation; } @@ -190,7 +190,7 @@ public: int get_collision_pairs() const { return collision_pairs; } - PhysicsDirectSpaceState3DSW *get_direct_state(); + GodotPhysicsDirectSpaceState3D *get_direct_state(); void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.is_empty(); } @@ -208,10 +208,10 @@ public: void set_elapsed_time(ElapsedTime p_time, uint64_t p_msec) { elapsed_time[p_time] = p_msec; } uint64_t get_elapsed_time(ElapsedTime p_time) const { return elapsed_time[p_time]; } - bool test_body_motion(Body3DSW *p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, PhysicsServer3D::MotionResult *r_result, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()); + bool test_body_motion(GodotBody3D *p_body, const PhysicsServer3D::MotionParameters &p_parameters, PhysicsServer3D::MotionResult *r_result); - Space3DSW(); - ~Space3DSW(); + GodotSpace3D(); + ~GodotSpace3D(); }; -#endif // SPACE__SW_H +#endif // GODOT_SPACE_3D_H diff --git a/servers/physics_3d/step_3d_sw.cpp b/servers/physics_3d/godot_step_3d.cpp index d0604b0aa0..5453c4415c 100644 --- a/servers/physics_3d/step_3d_sw.cpp +++ b/servers/physics_3d/godot_step_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* step_3d_sw.cpp */ +/* godot_step_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,8 +28,9 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "step_3d_sw.h" -#include "joints_3d_sw.h" +#include "godot_step_3d.h" + +#include "godot_joint_3d.h" #include "core/os/os.h" @@ -39,7 +40,7 @@ #define ISLAND_SIZE_RESERVE 512 #define CONSTRAINT_COUNT_RESERVE 1024 -void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) { +void GodotStep3D::_populate_island(GodotBody3D *p_body, LocalVector<GodotBody3D *> &p_body_island, LocalVector<GodotConstraint3D *> &p_constraint_island) { p_body->set_island_step(_step); if (p_body->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC) { @@ -47,8 +48,8 @@ void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_bod p_body_island.push_back(p_body); } - for (Map<Constraint3DSW *, int>::Element *E = p_body->get_constraint_map().front(); E; E = E->next()) { - Constraint3DSW *constraint = (Constraint3DSW *)E->key(); + for (const KeyValue<GodotConstraint3D *, int> &E : p_body->get_constraint_map()) { + GodotConstraint3D *constraint = (GodotConstraint3D *)E.key; if (constraint->get_island_step() == _step) { continue; // Already processed. } @@ -59,10 +60,10 @@ void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_bod // Find connected rigid bodies. for (int i = 0; i < constraint->get_body_count(); i++) { - if (i == E->get()) { + if (i == E.value) { continue; } - Body3DSW *other_body = constraint->get_body_ptr()[i]; + GodotBody3D *other_body = constraint->get_body_ptr()[i]; if (other_body->get_island_step() == _step) { continue; // Already processed. } @@ -74,7 +75,7 @@ void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_bod // Find connected soft bodies. for (int i = 0; i < constraint->get_soft_body_count(); i++) { - SoftBody3DSW *soft_body = constraint->get_soft_body_ptr(i); + GodotSoftBody3D *soft_body = constraint->get_soft_body_ptr(i); if (soft_body->get_island_step() == _step) { continue; // Already processed. } @@ -83,11 +84,11 @@ void Step3DSW::_populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_bod } } -void Step3DSW::_populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island) { +void GodotStep3D::_populate_island_soft_body(GodotSoftBody3D *p_soft_body, LocalVector<GodotBody3D *> &p_body_island, LocalVector<GodotConstraint3D *> &p_constraint_island) { p_soft_body->set_island_step(_step); - for (Set<Constraint3DSW *>::Element *E = p_soft_body->get_constraints().front(); E; E = E->next()) { - Constraint3DSW *constraint = (Constraint3DSW *)E->get(); + for (Set<GodotConstraint3D *>::Element *E = p_soft_body->get_constraints().front(); E; E = E->next()) { + GodotConstraint3D *constraint = (GodotConstraint3D *)E->get(); if (constraint->get_island_step() == _step) { continue; // Already processed. } @@ -98,7 +99,7 @@ void Step3DSW::_populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector // Find connected rigid bodies. for (int i = 0; i < constraint->get_body_count(); i++) { - Body3DSW *body = constraint->get_body_ptr()[i]; + GodotBody3D *body = constraint->get_body_ptr()[i]; if (body->get_island_step() == _step) { continue; // Already processed. } @@ -110,16 +111,16 @@ void Step3DSW::_populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector } } -void Step3DSW::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) { - Constraint3DSW *constraint = all_constraints[p_constraint_index]; +void GodotStep3D::_setup_contraint(uint32_t p_constraint_index, void *p_userdata) { + GodotConstraint3D *constraint = all_constraints[p_constraint_index]; constraint->setup(delta); } -void Step3DSW::_pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island) const { +void GodotStep3D::_pre_solve_island(LocalVector<GodotConstraint3D *> &p_constraint_island) const { uint32_t constraint_count = p_constraint_island.size(); uint32_t valid_constraint_count = 0; for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) { - Constraint3DSW *constraint = p_constraint_island[constraint_index]; + GodotConstraint3D *constraint = p_constraint_island[constraint_index]; if (p_constraint_island[constraint_index]->pre_solve(delta)) { // Keep this constraint for solving. p_constraint_island[valid_constraint_count++] = constraint; @@ -128,8 +129,8 @@ void Step3DSW::_pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_isl p_constraint_island.resize(valid_constraint_count); } -void Step3DSW::_solve_island(uint32_t p_island_index, void *p_userdata) { - LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[p_island_index]; +void GodotStep3D::_solve_island(uint32_t p_island_index, void *p_userdata) { + LocalVector<GodotConstraint3D *> &constraint_island = constraint_islands[p_island_index]; int current_priority = 1; @@ -146,7 +147,7 @@ void Step3DSW::_solve_island(uint32_t p_island_index, void *p_userdata) { uint32_t priority_constraint_count = 0; ++current_priority; for (uint32_t constraint_index = 0; constraint_index < constraint_count; ++constraint_index) { - Constraint3DSW *constraint = constraint_island[constraint_index]; + GodotConstraint3D *constraint = constraint_island[constraint_index]; if (constraint->get_priority() >= current_priority) { // Keep this constraint for the next iteration. constraint_island[priority_constraint_count++] = constraint; @@ -156,12 +157,12 @@ void Step3DSW::_solve_island(uint32_t p_island_index, void *p_userdata) { } } -void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island) const { +void GodotStep3D::_check_suspend(const LocalVector<GodotBody3D *> &p_body_island) const { bool can_sleep = true; uint32_t body_count = p_body_island.size(); for (uint32_t body_index = 0; body_index < body_count; ++body_index) { - Body3DSW *body = p_body_island[body_index]; + GodotBody3D *body = p_body_island[body_index]; if (!body->sleep_test(delta)) { can_sleep = false; @@ -170,7 +171,7 @@ void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island) cons // Put all to sleep or wake up everyone. for (uint32_t body_index = 0; body_index < body_count; ++body_index) { - Body3DSW *body = p_body_island[body_index]; + GodotBody3D *body = p_body_island[body_index]; bool active = body->is_active(); @@ -180,7 +181,7 @@ void Step3DSW::_check_suspend(const LocalVector<Body3DSW *> &p_body_island) cons } } -void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { +void GodotStep3D::step(GodotSpace3D *p_space, real_t p_delta, int p_iterations) { p_space->lock(); // can't access space during this p_space->setup(); //update inertias, etc @@ -190,9 +191,9 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { iterations = p_iterations; delta = p_delta; - const SelfList<Body3DSW>::List *body_list = &p_space->get_active_body_list(); + const SelfList<GodotBody3D>::List *body_list = &p_space->get_active_body_list(); - const SelfList<SoftBody3DSW>::List *soft_body_list = &p_space->get_active_soft_body_list(); + const SelfList<GodotSoftBody3D>::List *soft_body_list = &p_space->get_active_soft_body_list(); /* INTEGRATE FORCES */ @@ -201,7 +202,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { int active_count = 0; - const SelfList<Body3DSW> *b = body_list->first(); + const SelfList<GodotBody3D> *b = body_list->first(); while (b) { b->self()->integrate_forces(p_delta); b = b->next(); @@ -210,7 +211,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { /* UPDATE SOFT BODY MOTION */ - const SelfList<SoftBody3DSW> *sb = soft_body_list->first(); + const SelfList<GodotSoftBody3D> *sb = soft_body_list->first(); while (sb) { sb->self()->predict_motion(p_delta); sb = sb->next(); @@ -219,9 +220,12 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { p_space->set_active_objects(active_count); + // Update the broadphase to register collision pairs. + p_space->update(); + { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_INTEGRATE_FORCES, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } @@ -229,11 +233,11 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { uint32_t island_count = 0; - const SelfList<Area3DSW>::List &aml = p_space->get_moved_area_list(); + const SelfList<GodotArea3D>::List &aml = p_space->get_moved_area_list(); while (aml.first()) { - for (const Set<Constraint3DSW *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) { - Constraint3DSW *constraint = E->get(); + for (const Set<GodotConstraint3D *>::Element *E = aml.first()->self()->get_constraints().front(); E; E = E->next()) { + GodotConstraint3D *constraint = E->get(); if (constraint->get_island_step() == _step) { continue; } @@ -244,13 +248,13 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { if (constraint_islands.size() < island_count) { constraint_islands.resize(island_count); } - LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1]; + LocalVector<GodotConstraint3D *> &constraint_island = constraint_islands[island_count - 1]; constraint_island.clear(); all_constraints.push_back(constraint); constraint_island.push_back(constraint); } - p_space->area_remove_from_moved_list((SelfList<Area3DSW> *)aml.first()); //faster to remove here + p_space->area_remove_from_moved_list((SelfList<GodotArea3D> *)aml.first()); //faster to remove here } /* GENERATE CONSTRAINT ISLANDS FOR ACTIVE RIGID BODIES */ @@ -260,14 +264,14 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { uint32_t body_island_count = 0; while (b) { - Body3DSW *body = b->self(); + GodotBody3D *body = b->self(); if (body->get_island_step() != _step) { ++body_island_count; if (body_islands.size() < body_island_count) { body_islands.resize(body_island_count); } - LocalVector<Body3DSW *> &body_island = body_islands[body_island_count - 1]; + LocalVector<GodotBody3D *> &body_island = body_islands[body_island_count - 1]; body_island.clear(); body_island.reserve(BODY_ISLAND_SIZE_RESERVE); @@ -275,7 +279,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { if (constraint_islands.size() < island_count) { constraint_islands.resize(island_count); } - LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1]; + LocalVector<GodotConstraint3D *> &constraint_island = constraint_islands[island_count - 1]; constraint_island.clear(); constraint_island.reserve(ISLAND_SIZE_RESERVE); @@ -296,14 +300,14 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { sb = soft_body_list->first(); while (sb) { - SoftBody3DSW *soft_body = sb->self(); + GodotSoftBody3D *soft_body = sb->self(); if (soft_body->get_island_step() != _step) { ++body_island_count; if (body_islands.size() < body_island_count) { body_islands.resize(body_island_count); } - LocalVector<Body3DSW *> &body_island = body_islands[body_island_count - 1]; + LocalVector<GodotBody3D *> &body_island = body_islands[body_island_count - 1]; body_island.clear(); body_island.reserve(BODY_ISLAND_SIZE_RESERVE); @@ -311,7 +315,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { if (constraint_islands.size() < island_count) { constraint_islands.resize(island_count); } - LocalVector<Constraint3DSW *> &constraint_island = constraint_islands[island_count - 1]; + LocalVector<GodotConstraint3D *> &constraint_island = constraint_islands[island_count - 1]; constraint_island.clear(); constraint_island.reserve(ISLAND_SIZE_RESERVE); @@ -332,18 +336,18 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_GENERATE_ISLANDS, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } /* SETUP CONSTRAINTS / PROCESS COLLISIONS */ uint32_t total_contraint_count = all_constraints.size(); - work_pool.do_work(total_contraint_count, this, &Step3DSW::_setup_contraint, nullptr); + work_pool.do_work(total_contraint_count, this, &GodotStep3D::_setup_contraint, nullptr); { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_SETUP_CONSTRAINTS, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } @@ -358,15 +362,11 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { // Warning: _solve_island modifies the constraint islands for optimization purpose, // their content is not reliable after these calls and shouldn't be used anymore. - if (island_count > 1) { - work_pool.do_work(island_count, this, &Step3DSW::_solve_island, nullptr); - } else if (island_count > 0) { - _solve_island(0); - } + work_pool.do_work(island_count, this, &GodotStep3D::_solve_island, nullptr); { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_SOLVE_CONSTRAINTS, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } @@ -374,7 +374,7 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { b = body_list->first(); while (b) { - const SelfList<Body3DSW> *n = b->next(); + const SelfList<GodotBody3D> *n = b->next(); b->self()->integrate_velocities(p_delta); b = n; } @@ -395,20 +395,17 @@ void Step3DSW::step(Space3DSW *p_space, real_t p_delta, int p_iterations) { { //profile profile_endtime = OS::get_singleton()->get_ticks_usec(); - p_space->set_elapsed_time(Space3DSW::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime); + p_space->set_elapsed_time(GodotSpace3D::ELAPSED_TIME_INTEGRATE_VELOCITIES, profile_endtime - profile_begtime); profile_begtime = profile_endtime; } all_constraints.clear(); - p_space->update(); p_space->unlock(); _step++; } -Step3DSW::Step3DSW() { - _step = 1; - +GodotStep3D::GodotStep3D() { body_islands.reserve(BODY_ISLAND_COUNT_RESERVE); constraint_islands.reserve(ISLAND_COUNT_RESERVE); all_constraints.reserve(CONSTRAINT_COUNT_RESERVE); @@ -416,6 +413,6 @@ Step3DSW::Step3DSW() { work_pool.init(); } -Step3DSW::~Step3DSW() { +GodotStep3D::~GodotStep3D() { work_pool.finish(); } diff --git a/servers/physics_3d/step_3d_sw.h b/servers/physics_3d/godot_step_3d.h index 9c60004b24..23ede4feff 100644 --- a/servers/physics_3d/step_3d_sw.h +++ b/servers/physics_3d/godot_step_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* step_3d_sw.h */ +/* godot_step_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,37 +28,37 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef STEP_SW_H -#define STEP_SW_H +#ifndef GODOT_STEP_3D_H +#define GODOT_STEP_3D_H -#include "space_3d_sw.h" +#include "godot_space_3d.h" #include "core/templates/local_vector.h" #include "core/templates/thread_work_pool.h" -class Step3DSW { - uint64_t _step; +class GodotStep3D { + uint64_t _step = 1; int iterations = 0; real_t delta = 0.0; ThreadWorkPool work_pool; - LocalVector<LocalVector<Body3DSW *>> body_islands; - LocalVector<LocalVector<Constraint3DSW *>> constraint_islands; - LocalVector<Constraint3DSW *> all_constraints; + LocalVector<LocalVector<GodotBody3D *>> body_islands; + LocalVector<LocalVector<GodotConstraint3D *>> constraint_islands; + LocalVector<GodotConstraint3D *> all_constraints; - void _populate_island(Body3DSW *p_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island); - void _populate_island_soft_body(SoftBody3DSW *p_soft_body, LocalVector<Body3DSW *> &p_body_island, LocalVector<Constraint3DSW *> &p_constraint_island); + void _populate_island(GodotBody3D *p_body, LocalVector<GodotBody3D *> &p_body_island, LocalVector<GodotConstraint3D *> &p_constraint_island); + void _populate_island_soft_body(GodotSoftBody3D *p_soft_body, LocalVector<GodotBody3D *> &p_body_island, LocalVector<GodotConstraint3D *> &p_constraint_island); void _setup_contraint(uint32_t p_constraint_index, void *p_userdata = nullptr); - void _pre_solve_island(LocalVector<Constraint3DSW *> &p_constraint_island) const; + void _pre_solve_island(LocalVector<GodotConstraint3D *> &p_constraint_island) const; void _solve_island(uint32_t p_island_index, void *p_userdata = nullptr); - void _check_suspend(const LocalVector<Body3DSW *> &p_body_island) const; + void _check_suspend(const LocalVector<GodotBody3D *> &p_body_island) const; public: - void step(Space3DSW *p_space, real_t p_delta, int p_iterations); - Step3DSW(); - ~Step3DSW(); + void step(GodotSpace3D *p_space, real_t p_delta, int p_iterations); + GodotStep3D(); + ~GodotStep3D(); }; -#endif // STEP__SW_H +#endif // GODOT_STEP_3D_H diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp b/servers/physics_3d/joints/godot_cone_twist_joint_3d.cpp index 7315e9c709..864086c956 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/godot_cone_twist_joint_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* cone_twist_joint_3d_sw.cpp */ +/* godot_cone_twist_joint_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -49,7 +49,7 @@ subject to the following restrictions: Written by: Marcus Hennix */ -#include "cone_twist_joint_3d_sw.h" +#include "godot_cone_twist_joint_3d.h" static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) { if (Math::abs(n.z) > Math_SQRT12) { @@ -84,31 +84,19 @@ static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) { return (y < 0.0f) ? -angle : angle; } -ConeTwistJoint3DSW::ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) : - Joint3DSW(_arr, 2) { +GodotConeTwistJoint3D::GodotConeTwistJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame) : + GodotJoint3D(_arr, 2) { A = rbA; B = rbB; m_rbAFrame = rbAFrame; m_rbBFrame = rbBFrame; - m_swingSpan1 = Math_TAU / 8.0; - m_swingSpan2 = Math_TAU / 8.0; - m_twistSpan = Math_TAU; - m_biasFactor = 0.3f; - m_relaxationFactor = 1.0f; - - m_angularOnly = false; - m_solveTwistLimit = false; - m_solveSwingLimit = false; - A->add_constraint(this, 0); B->add_constraint(this, 1); - - m_appliedImpulse = 0; } -bool ConeTwistJoint3DSW::setup(real_t p_timestep) { +bool GodotConeTwistJoint3D::setup(real_t p_timestep) { dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); @@ -141,16 +129,18 @@ bool ConeTwistJoint3DSW::setup(real_t p_timestep) { plane_space(normal[0], normal[1], normal[2]); for (int i = 0; i < 3; i++) { - memnew_placement(&m_jac[i], JacobianEntry3DSW( - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - pivotAInW - A->get_transform().origin - A->get_center_of_mass(), - pivotBInW - B->get_transform().origin - B->get_center_of_mass(), - normal[i], - A->get_inv_inertia(), - A->get_inv_mass(), - B->get_inv_inertia(), - B->get_inv_mass())); + memnew_placement( + &m_jac[i], + GodotJacobianEntry3D( + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + pivotAInW - A->get_transform().origin - A->get_center_of_mass(), + pivotBInW - B->get_transform().origin - B->get_center_of_mass(), + normal[i], + A->get_inv_inertia(), + A->get_inv_mass(), + B->get_inv_inertia(), + B->get_inv_mass())); } } @@ -204,8 +194,7 @@ bool ConeTwistJoint3DSW::setup(real_t p_timestep) { real_t swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f; m_swingAxis *= swingAxisSign; - m_kSwing = real_t(1.) / (A->compute_angular_impulse_denominator(m_swingAxis) + - B->compute_angular_impulse_denominator(m_swingAxis)); + m_kSwing = real_t(1.) / (A->compute_angular_impulse_denominator(m_swingAxis) + B->compute_angular_impulse_denominator(m_swingAxis)); } // Twist limits @@ -224,8 +213,7 @@ bool ConeTwistJoint3DSW::setup(real_t p_timestep) { m_twistAxis.normalize(); m_twistAxis *= -1.0f; - m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) + - B->compute_angular_impulse_denominator(m_twistAxis)); + m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) + B->compute_angular_impulse_denominator(m_twistAxis)); } else if (twist > m_twistSpan * lockedFreeFactor) { m_twistCorrection = (twist - m_twistSpan); @@ -234,15 +222,14 @@ bool ConeTwistJoint3DSW::setup(real_t p_timestep) { m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f; m_twistAxis.normalize(); - m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) + - B->compute_angular_impulse_denominator(m_twistAxis)); + m_kTwist = real_t(1.) / (A->compute_angular_impulse_denominator(m_twistAxis) + B->compute_angular_impulse_denominator(m_twistAxis)); } } return true; } -void ConeTwistJoint3DSW::solve(real_t p_timestep) { +void GodotConeTwistJoint3D::solve(real_t p_timestep) { Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin); Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin); @@ -324,7 +311,7 @@ void ConeTwistJoint3DSW::solve(real_t p_timestep) { } } -void ConeTwistJoint3DSW::set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value) { +void GodotConeTwistJoint3D::set_param(PhysicsServer3D::ConeTwistJointParam p_param, real_t p_value) { switch (p_param) { case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: { m_swingSpan1 = p_value; @@ -347,7 +334,7 @@ void ConeTwistJoint3DSW::set_param(PhysicsServer3D::ConeTwistJointParam p_param, } } -real_t ConeTwistJoint3DSW::get_param(PhysicsServer3D::ConeTwistJointParam p_param) const { +real_t GodotConeTwistJoint3D::get_param(PhysicsServer3D::ConeTwistJointParam p_param) const { switch (p_param) { case PhysicsServer3D::CONE_TWIST_JOINT_SWING_SPAN: { return m_swingSpan1; diff --git a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h b/servers/physics_3d/joints/godot_cone_twist_joint_3d.h index 608847352c..999d0f0692 100644 --- a/servers/physics_3d/joints/cone_twist_joint_3d_sw.h +++ b/servers/physics_3d/joints/godot_cone_twist_joint_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* cone_twist_joint_3d_sw.h */ +/* godot_cone_twist_joint_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library. /* Bullet Continuous Collision Detection and Physics Library -ConeTwistJointSW is Copyright (c) 2007 Starbreeze Studios +GodotConeTwistJoint3D is Copyright (c) 2007 Starbreeze Studios This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -49,57 +49,57 @@ subject to the following restrictions: Written by: Marcus Hennix */ -#ifndef CONE_TWIST_JOINT_SW_H -#define CONE_TWIST_JOINT_SW_H +#ifndef GODOT_CONE_TWIST_JOINT_3D_H +#define GODOT_CONE_TWIST_JOINT_3D_H -#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h" -#include "servers/physics_3d/joints_3d_sw.h" +#include "servers/physics_3d/godot_joint_3d.h" +#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" -///ConeTwistJointSW can be used to simulate ragdoll joints (upper arm, leg etc) -class ConeTwistJoint3DSW : public Joint3DSW { +// GodotConeTwistJoint3D can be used to simulate ragdoll joints (upper arm, leg etc). +class GodotConeTwistJoint3D : public GodotJoint3D { #ifdef IN_PARALLELL_SOLVER public: #endif union { struct { - Body3DSW *A; - Body3DSW *B; + GodotBody3D *A; + GodotBody3D *B; }; - Body3DSW *_arr[2]; + GodotBody3D *_arr[2] = { nullptr, nullptr }; }; - JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints + GodotJacobianEntry3D m_jac[3] = {}; //3 orthogonal linear constraints - real_t m_appliedImpulse; + real_t m_appliedImpulse = 0.0; Transform3D m_rbAFrame; Transform3D m_rbBFrame; - real_t m_limitSoftness; - real_t m_biasFactor; - real_t m_relaxationFactor; + real_t m_limitSoftness = 0.0; + real_t m_biasFactor = 0.3; + real_t m_relaxationFactor = 1.0; - real_t m_swingSpan1; - real_t m_swingSpan2; - real_t m_twistSpan; + real_t m_swingSpan1 = Math_TAU / 8.0; + real_t m_swingSpan2 = 0.0; + real_t m_twistSpan = 0.0; Vector3 m_swingAxis; Vector3 m_twistAxis; - real_t m_kSwing; - real_t m_kTwist; + real_t m_kSwing = 0.0; + real_t m_kTwist = 0.0; - real_t m_twistLimitSign; - real_t m_swingCorrection; - real_t m_twistCorrection; + real_t m_twistLimitSign = 0.0; + real_t m_swingCorrection = 0.0; + real_t m_twistCorrection = 0.0; - real_t m_accSwingLimitImpulse; - real_t m_accTwistLimitImpulse; + real_t m_accSwingLimitImpulse = 0.0; + real_t m_accTwistLimitImpulse = 0.0; - bool m_angularOnly; - bool m_solveTwistLimit; - bool m_solveSwingLimit; + bool m_angularOnly = false; + bool m_solveTwistLimit = false; + bool m_solveSwingLimit = false; public: virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_CONE_TWIST; } @@ -107,7 +107,7 @@ public: virtual bool setup(real_t p_step) override; virtual void solve(real_t p_step) override; - ConeTwistJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame); + GodotConeTwistJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &rbAFrame, const Transform3D &rbBFrame); void setAngularOnly(bool angularOnly) { m_angularOnly = angularOnly; @@ -139,4 +139,4 @@ public: real_t get_param(PhysicsServer3D::ConeTwistJointParam p_param) const; }; -#endif // CONE_TWIST_JOINT_SW_H +#endif // GODOT_CONE_TWIST_JOINT_3D_H diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp b/servers/physics_3d/joints/godot_generic_6dof_joint_3d.cpp index d2b64ce6e3..915bb528e9 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/godot_generic_6dof_joint_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* generic_6dof_joint_3d_sw.cpp */ +/* godot_generic_6dof_joint_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library. /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -49,18 +49,18 @@ subject to the following restrictions: /* 2007-09-09 -Generic6DOFJointSW Refactored by Francisco Le?n +GodotGeneric6DOFJoint3D Refactored by Francisco Le?n email: projectileman@yahoo.com http://gimpact.sf.net */ -#include "generic_6dof_joint_3d_sw.h" +#include "godot_generic_6dof_joint_3d.h" #define GENERIC_D6_DISABLE_WARMSTARTING 1 -//////////////////////////// G6DOFRotationalLimitMotorSW //////////////////////////////////// +//////////////////////////// GodotG6DOFRotationalLimitMotor3D //////////////////////////////////// -int G6DOFRotationalLimitMotor3DSW::testLimitValue(real_t test_value) { +int GodotG6DOFRotationalLimitMotor3D::testLimitValue(real_t test_value) { if (m_loLimit > m_hiLimit) { m_currentLimit = 0; //Free from violation return 0; @@ -80,9 +80,9 @@ int G6DOFRotationalLimitMotor3DSW::testLimitValue(real_t test_value) { return 0; } -real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits( +real_t GodotG6DOFRotationalLimitMotor3D::solveAngularLimits( real_t timeStep, Vector3 &axis, real_t jacDiagABInv, - Body3DSW *body0, Body3DSW *body1, bool p_body0_dynamic, bool p_body1_dynamic) { + GodotBody3D *body0, GodotBody3D *body1, bool p_body0_dynamic, bool p_body1_dynamic) { if (!needApplyTorques()) { return 0.0f; } @@ -148,14 +148,13 @@ real_t G6DOFRotationalLimitMotor3DSW::solveAngularLimits( return clippedMotorImpulse; } -//////////////////////////// End G6DOFRotationalLimitMotorSW //////////////////////////////////// +//////////////////////////// GodotG6DOFTranslationalLimitMotor3D //////////////////////////////////// -//////////////////////////// G6DOFTranslationalLimitMotorSW //////////////////////////////////// -real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis( +real_t GodotG6DOFTranslationalLimitMotor3D::solveLinearAxis( real_t timeStep, real_t jacDiagABInv, - Body3DSW *body1, const Vector3 &pointInA, - Body3DSW *body2, const Vector3 &pointInB, + GodotBody3D *body1, const Vector3 &pointInA, + GodotBody3D *body2, const Vector3 &pointInB, bool p_body1_dynamic, bool p_body2_dynamic, int limit_index, const Vector3 &axis_normal_on_a, @@ -217,10 +216,10 @@ real_t G6DOFTranslationalLimitMotor3DSW::solveLinearAxis( return normalImpulse; } -//////////////////////////// G6DOFTranslationalLimitMotorSW //////////////////////////////////// +//////////////////////////// GodotGeneric6DOFJoint3D //////////////////////////////////// -Generic6DOFJoint3DSW::Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB, bool useLinearReferenceFrameA) : - Joint3DSW(_arr, 2), +GodotGeneric6DOFJoint3D::GodotGeneric6DOFJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &frameInA, const Transform3D &frameInB, bool useLinearReferenceFrameA) : + GodotJoint3D(_arr, 2), m_frameInA(frameInA), m_frameInB(frameInB), m_useLinearReferenceFrameA(useLinearReferenceFrameA) { @@ -230,10 +229,10 @@ Generic6DOFJoint3DSW::Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const T B->add_constraint(this, 1); } -void Generic6DOFJoint3DSW::calculateAngleInfo() { +void GodotGeneric6DOFJoint3D::calculateAngleInfo() { Basis relative_frame = m_calculatedTransformB.basis.inverse() * m_calculatedTransformA.basis; - m_calculatedAxisAngleDiff = relative_frame.get_euler_xyz(); + m_calculatedAxisAngleDiff = relative_frame.get_euler(Basis::EULER_ORDER_XYZ); // in euler angle mode we do not actually constrain the angular velocity // along the axes axis[0] and axis[2] (although we do use axis[1]) : @@ -270,38 +269,43 @@ void Generic6DOFJoint3DSW::calculateAngleInfo() { */ } -void Generic6DOFJoint3DSW::calculateTransforms() { +void GodotGeneric6DOFJoint3D::calculateTransforms() { m_calculatedTransformA = A->get_transform() * m_frameInA; m_calculatedTransformB = B->get_transform() * m_frameInB; calculateAngleInfo(); } -void Generic6DOFJoint3DSW::buildLinearJacobian( - JacobianEntry3DSW &jacLinear, const Vector3 &normalWorld, +void GodotGeneric6DOFJoint3D::buildLinearJacobian( + GodotJacobianEntry3D &jacLinear, const Vector3 &normalWorld, const Vector3 &pivotAInW, const Vector3 &pivotBInW) { - memnew_placement(&jacLinear, JacobianEntry3DSW( - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - pivotAInW - A->get_transform().origin - A->get_center_of_mass(), - pivotBInW - B->get_transform().origin - B->get_center_of_mass(), - normalWorld, - A->get_inv_inertia(), - A->get_inv_mass(), - B->get_inv_inertia(), - B->get_inv_mass())); + memnew_placement( + &jacLinear, + GodotJacobianEntry3D( + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + pivotAInW - A->get_transform().origin - A->get_center_of_mass(), + pivotBInW - B->get_transform().origin - B->get_center_of_mass(), + normalWorld, + A->get_inv_inertia(), + A->get_inv_mass(), + B->get_inv_inertia(), + B->get_inv_mass())); } -void Generic6DOFJoint3DSW::buildAngularJacobian( - JacobianEntry3DSW &jacAngular, const Vector3 &jointAxisW) { - memnew_placement(&jacAngular, JacobianEntry3DSW(jointAxisW, - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - A->get_inv_inertia(), - B->get_inv_inertia())); +void GodotGeneric6DOFJoint3D::buildAngularJacobian( + GodotJacobianEntry3D &jacAngular, const Vector3 &jointAxisW) { + memnew_placement( + &jacAngular, + GodotJacobianEntry3D( + jointAxisW, + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + A->get_inv_inertia(), + B->get_inv_inertia())); } -bool Generic6DOFJoint3DSW::testAngularLimitMotor(int axis_index) { +bool GodotGeneric6DOFJoint3D::testAngularLimitMotor(int axis_index) { real_t angle = m_calculatedAxisAngleDiff[axis_index]; //test limits @@ -309,7 +313,7 @@ bool Generic6DOFJoint3DSW::testAngularLimitMotor(int axis_index) { return m_angularLimits[axis_index].needApplyTorques(); } -bool Generic6DOFJoint3DSW::setup(real_t p_timestep) { +bool GodotGeneric6DOFJoint3D::setup(real_t p_timestep) { dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); @@ -365,7 +369,7 @@ bool Generic6DOFJoint3DSW::setup(real_t p_timestep) { return true; } -void Generic6DOFJoint3DSW::solve(real_t p_timestep) { +void GodotGeneric6DOFJoint3D::solve(real_t p_timestep) { m_timeStep = p_timestep; //calculateTransforms(); @@ -414,19 +418,19 @@ void Generic6DOFJoint3DSW::solve(real_t p_timestep) { } } -void Generic6DOFJoint3DSW::updateRHS(real_t timeStep) { +void GodotGeneric6DOFJoint3D::updateRHS(real_t timeStep) { (void)timeStep; } -Vector3 Generic6DOFJoint3DSW::getAxis(int axis_index) const { +Vector3 GodotGeneric6DOFJoint3D::getAxis(int axis_index) const { return m_calculatedAxis[axis_index]; } -real_t Generic6DOFJoint3DSW::getAngle(int axis_index) const { +real_t GodotGeneric6DOFJoint3D::getAngle(int axis_index) const { return m_calculatedAxisAngleDiff[axis_index]; } -void Generic6DOFJoint3DSW::calcAnchorPos() { +void GodotGeneric6DOFJoint3D::calcAnchorPos() { real_t imA = A->get_inv_mass(); real_t imB = B->get_inv_mass(); real_t weight; @@ -438,9 +442,9 @@ void Generic6DOFJoint3DSW::calcAnchorPos() { const Vector3 &pA = m_calculatedTransformA.origin; const Vector3 &pB = m_calculatedTransformB.origin; m_AnchorPos = pA * weight + pB * (real_t(1.0) - weight); -} // Generic6DOFJointSW::calcAnchorPos() +} -void Generic6DOFJoint3DSW::set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param, real_t p_value) { +void GodotGeneric6DOFJoint3D::set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param, real_t p_value) { ERR_FAIL_INDEX(p_axis, 3); switch (p_param) { case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT: { @@ -527,7 +531,7 @@ void Generic6DOFJoint3DSW::set_param(Vector3::Axis p_axis, PhysicsServer3D::G6DO } } -real_t Generic6DOFJoint3DSW::get_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param) const { +real_t GodotGeneric6DOFJoint3D::get_param(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisParam p_param) const { ERR_FAIL_INDEX_V(p_axis, 3, 0); switch (p_param) { case PhysicsServer3D::G6DOF_JOINT_LINEAR_LOWER_LIMIT: { @@ -615,7 +619,7 @@ real_t Generic6DOFJoint3DSW::get_param(Vector3::Axis p_axis, PhysicsServer3D::G6 return 0; } -void Generic6DOFJoint3DSW::set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value) { +void GodotGeneric6DOFJoint3D::set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag, bool p_value) { ERR_FAIL_INDEX(p_axis, 3); switch (p_flag) { @@ -642,7 +646,7 @@ void Generic6DOFJoint3DSW::set_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOF } } -bool Generic6DOFJoint3DSW::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const { +bool GodotGeneric6DOFJoint3D::get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const { ERR_FAIL_INDEX_V(p_axis, 3, 0); switch (p_flag) { case PhysicsServer3D::G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT: { diff --git a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h b/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h index c2a0443aff..f37b5b981b 100644 --- a/servers/physics_3d/joints/generic_6dof_joint_3d_sw.h +++ b/servers/physics_3d/joints/godot_generic_6dof_joint_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* generic_6dof_joint_3d_sw.h */ +/* godot_generic_6dof_joint_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -32,15 +32,15 @@ Adapted to Godot from the Bullet library. */ -#ifndef GENERIC_6DOF_JOINT_SW_H -#define GENERIC_6DOF_JOINT_SW_H +#ifndef GODOT_GENERIC_6DOF_JOINT_3D_H +#define GODOT_GENERIC_6DOF_JOINT_3D_H -#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h" -#include "servers/physics_3d/joints_3d_sw.h" +#include "servers/physics_3d/godot_joint_3d.h" +#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -55,108 +55,75 @@ subject to the following restrictions: /* 2007-09-09 -Generic6DOFJointSW Refactored by Francisco Le?n +GodotGeneric6DOFJoint3D Refactored by Francisco Le?n email: projectileman@yahoo.com http://gimpact.sf.net */ //! Rotation Limit structure for generic joints -class G6DOFRotationalLimitMotor3DSW { +class GodotG6DOFRotationalLimitMotor3D { public: //! limit_parameters //!@{ - real_t m_loLimit; //!< joint limit - real_t m_hiLimit; //!< joint limit - real_t m_targetVelocity; //!< target motor velocity - real_t m_maxMotorForce; //!< max force on motor - real_t m_maxLimitForce; //!< max force on limit - real_t m_damping; //!< Damping. - real_t m_limitSoftness; //! Relaxation factor - real_t m_ERP; //!< Error tolerance factor when joint is at limit - real_t m_bounce; //!< restitution factor - bool m_enableMotor; - bool m_enableLimit; + real_t m_loLimit = -1e30; //!< joint limit + real_t m_hiLimit = 1e30; //!< joint limit + real_t m_targetVelocity = 0.0; //!< target motor velocity + real_t m_maxMotorForce = 0.1; //!< max force on motor + real_t m_maxLimitForce = 300.0; //!< max force on limit + real_t m_damping = 1.0; //!< Damping. + real_t m_limitSoftness = 0.5; //! Relaxation factor + real_t m_ERP = 0.5; //!< Error tolerance factor when joint is at limit + real_t m_bounce = 0.0; //!< restitution factor + bool m_enableMotor = false; + bool m_enableLimit = false; //!@} //! temp_variables //!@{ - real_t m_currentLimitError; //!< How much is violated this limit - int m_currentLimit; //!< 0=free, 1=at lo limit, 2=at hi limit - real_t m_accumulatedImpulse; + real_t m_currentLimitError = 0.0; //!< How much is violated this limit + int m_currentLimit = 0; //!< 0=free, 1=at lo limit, 2=at hi limit + real_t m_accumulatedImpulse = 0.0; //!@} - G6DOFRotationalLimitMotor3DSW() { - m_accumulatedImpulse = 0.f; - m_targetVelocity = 0; - m_maxMotorForce = 0.1f; - m_maxLimitForce = 300.0f; - m_loLimit = -1e30; - m_hiLimit = 1e30; - m_ERP = 0.5f; - m_bounce = 0.0f; - m_damping = 1.0f; - m_limitSoftness = 0.5f; - m_currentLimit = 0; - m_currentLimitError = 0; - m_enableMotor = false; - m_enableLimit = false; - } + GodotG6DOFRotationalLimitMotor3D() {} - //! Is limited bool isLimited() { return (m_loLimit < m_hiLimit); } - //! Need apply correction + // Need apply correction. bool needApplyTorques() { return (m_enableMotor || m_currentLimit != 0); } - //! calculates error - /*! - calculates m_currentLimit and m_currentLimitError. - */ + // Calculates m_currentLimit and m_currentLimitError. int testLimitValue(real_t test_value); - //! apply the correction impulses for two bodies - real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, Body3DSW *body0, Body3DSW *body1, bool p_body0_dynamic, bool p_body1_dynamic); + // Apply the correction impulses for two bodies. + real_t solveAngularLimits(real_t timeStep, Vector3 &axis, real_t jacDiagABInv, GodotBody3D *body0, GodotBody3D *body1, bool p_body0_dynamic, bool p_body1_dynamic); }; -class G6DOFTranslationalLimitMotor3DSW { +class GodotG6DOFTranslationalLimitMotor3D { public: - Vector3 m_lowerLimit; //!< the constraint lower limits - Vector3 m_upperLimit; //!< the constraint upper limits - Vector3 m_accumulatedImpulse; + Vector3 m_lowerLimit = Vector3(0.0, 0.0, 0.0); //!< the constraint lower limits + Vector3 m_upperLimit = Vector3(0.0, 0.0, 0.0); //!< the constraint upper limits + Vector3 m_accumulatedImpulse = Vector3(0.0, 0.0, 0.0); //! Linear_Limit_parameters //!@{ - Vector3 m_limitSoftness; //!< Softness for linear limit - Vector3 m_damping; //!< Damping for linear limit - Vector3 m_restitution; //! Bounce parameter for linear limit + Vector3 m_limitSoftness = Vector3(0.7, 0.7, 0.7); //!< Softness for linear limit + Vector3 m_damping = Vector3(1.0, 1.0, 1.0); //!< Damping for linear limit + Vector3 m_restitution = Vector3(0.5, 0.5, 0.5); //! Bounce parameter for linear limit //!@} - bool enable_limit[3]; - - G6DOFTranslationalLimitMotor3DSW() { - m_lowerLimit = Vector3(0.f, 0.f, 0.f); - m_upperLimit = Vector3(0.f, 0.f, 0.f); - m_accumulatedImpulse = Vector3(0.f, 0.f, 0.f); - - m_limitSoftness = Vector3(1, 1, 1) * 0.7f; - m_damping = Vector3(1, 1, 1) * real_t(1.0f); - m_restitution = Vector3(1, 1, 1) * real_t(0.5f); - - enable_limit[0] = true; - enable_limit[1] = true; - enable_limit[2] = true; - } + bool enable_limit[3] = { true, true, true }; //! Test limit /*! - - free means upper < lower, - - locked means upper == lower - - limited means upper > lower - - limitIndex: first 3 are linear, next 3 are angular - */ + * - free means upper < lower, + * - locked means upper == lower + * - limited means upper > lower + * - limitIndex: first 3 are linear, next 3 are angular + */ inline bool isLimited(int limitIndex) { return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]); } @@ -164,23 +131,23 @@ public: real_t solveLinearAxis( real_t timeStep, real_t jacDiagABInv, - Body3DSW *body1, const Vector3 &pointInA, - Body3DSW *body2, const Vector3 &pointInB, + GodotBody3D *body1, const Vector3 &pointInA, + GodotBody3D *body2, const Vector3 &pointInB, bool p_body1_dynamic, bool p_body2_dynamic, int limit_index, const Vector3 &axis_normal_on_a, const Vector3 &anchorPos); }; -class Generic6DOFJoint3DSW : public Joint3DSW { +class GodotGeneric6DOFJoint3D : public GodotJoint3D { protected: union { struct { - Body3DSW *A; - Body3DSW *B; + GodotBody3D *A; + GodotBody3D *B; }; - Body3DSW *_arr[2]; + GodotBody3D *_arr[2] = { nullptr, nullptr }; }; //! relative_frames @@ -191,24 +158,24 @@ protected: //! Jacobians //!@{ - JacobianEntry3DSW m_jacLinear[3]; //!< 3 orthogonal linear constraints - JacobianEntry3DSW m_jacAng[3]; //!< 3 orthogonal angular constraints + GodotJacobianEntry3D m_jacLinear[3]; //!< 3 orthogonal linear constraints + GodotJacobianEntry3D m_jacAng[3]; //!< 3 orthogonal angular constraints //!@} //! Linear_Limit_parameters //!@{ - G6DOFTranslationalLimitMotor3DSW m_linearLimits; + GodotG6DOFTranslationalLimitMotor3D m_linearLimits; //!@} //! hinge_parameters //!@{ - G6DOFRotationalLimitMotor3DSW m_angularLimits[3]; + GodotG6DOFRotationalLimitMotor3D m_angularLimits[3]; //!@} protected: //! temporal variables //!@{ - real_t m_timeStep; + real_t m_timeStep = 0.0; Transform3D m_calculatedTransformA; Transform3D m_calculatedTransformB; Vector3 m_calculatedAxisAngleDiff; @@ -216,49 +183,39 @@ protected: Vector3 m_AnchorPos; // point between pivots of bodies A and B to solve linear axes - bool m_useLinearReferenceFrameA; + bool m_useLinearReferenceFrameA = false; //!@} - Generic6DOFJoint3DSW(Generic6DOFJoint3DSW const &) = delete; - void operator=(Generic6DOFJoint3DSW const &) = delete; + GodotGeneric6DOFJoint3D(GodotGeneric6DOFJoint3D const &) = delete; + void operator=(GodotGeneric6DOFJoint3D const &) = delete; void buildLinearJacobian( - JacobianEntry3DSW &jacLinear, const Vector3 &normalWorld, + GodotJacobianEntry3D &jacLinear, const Vector3 &normalWorld, const Vector3 &pivotAInW, const Vector3 &pivotBInW); - void buildAngularJacobian(JacobianEntry3DSW &jacAngular, const Vector3 &jointAxisW); + void buildAngularJacobian(GodotJacobianEntry3D &jacAngular, const Vector3 &jointAxisW); //! calcs the euler angles between the two bodies. void calculateAngleInfo(); public: - Generic6DOFJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB, bool useLinearReferenceFrameA); + GodotGeneric6DOFJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &frameInA, const Transform3D &frameInB, bool useLinearReferenceFrameA); virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_6DOF; } virtual bool setup(real_t p_step) override; virtual void solve(real_t p_step) override; - //! Calcs global transform of the offsets - /*! - Calcs the global transform for the joint offset for body A an B, and also calcs the agle differences between the bodies. - \sa Generic6DOFJointSW.getCalculatedTransformA , Generic6DOFJointSW.getCalculatedTransformB, Generic6DOFJointSW.calculateAngleInfo - */ + // Calcs the global transform for the joint offset for body A an B, and also calcs the angle differences between the bodies. void calculateTransforms(); - //! Gets the global transform of the offset for body A - /*! - \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo. - */ + // Gets the global transform of the offset for body A. const Transform3D &getCalculatedTransformA() const { return m_calculatedTransformA; } - //! Gets the global transform of the offset for body B - /*! - \sa Generic6DOFJointSW.getFrameOffsetA, Generic6DOFJointSW.getFrameOffsetB, Generic6DOFJointSW.calculateAngleInfo. - */ + // Gets the global transform of the offset for body B. const Transform3D &getCalculatedTransformB() const { return m_calculatedTransformB; } @@ -279,27 +236,16 @@ public: return m_frameInB; } - //! performs Jacobian calculation, and also calculates angle differences and axis - + // Performs Jacobian calculation, and also calculates angle differences and axis. void updateRHS(real_t timeStep); - //! Get the rotation axis in global coordinates - /*! - \pre Generic6DOFJointSW.buildJacobian must be called previously. - */ + // Get the rotation axis in global coordinates. Vector3 getAxis(int axis_index) const; - //! Get the relative Euler angle - /*! - \pre Generic6DOFJointSW.buildJacobian must be called previously. - */ + // Get the relative Euler angle. real_t getAngle(int axis_index) const; - //! Test angular limit. - /*! - Calculates angular correction and returns true if limit needs to be corrected. - \pre Generic6DOFJointSW.buildJacobian must be called previously. - */ + // Calculates angular correction and returns true if limit needs to be corrected. bool testAngularLimitMotor(int axis_index); void setLinearLowerLimit(const Vector3 &linearLower) { @@ -322,17 +268,17 @@ public: m_angularLimits[2].m_hiLimit = angularUpper.z; } - //! Retrieves the angular limit information. - G6DOFRotationalLimitMotor3DSW *getRotationalLimitMotor(int index) { + // Retrieves the angular limit information. + GodotG6DOFRotationalLimitMotor3D *getRotationalLimitMotor(int index) { return &m_angularLimits[index]; } - //! Retrieves the limit information. - G6DOFTranslationalLimitMotor3DSW *getTranslationalLimitMotor() { + // Retrieves the limit information. + GodotG6DOFTranslationalLimitMotor3D *getTranslationalLimitMotor() { return &m_linearLimits; } - //first 3 are linear, next 3 are angular + // First 3 are linear, next 3 are angular. void setLimit(int axis, real_t lo, real_t hi) { if (axis < 3) { m_linearLimits.m_lowerLimit[axis] = lo; @@ -345,11 +291,11 @@ public: //! Test limit /*! - - free means upper < lower, - - locked means upper == lower - - limited means upper > lower - - limitIndex: first 3 are linear, next 3 are angular - */ + * - free means upper < lower, + * - locked means upper == lower + * - limited means upper > lower + * - limitIndex: first 3 are linear, next 3 are angular + */ bool isLimited(int limitIndex) { if (limitIndex < 3) { return m_linearLimits.isLimited(limitIndex); @@ -357,10 +303,10 @@ public: return m_angularLimits[limitIndex - 3].isLimited(); } - const Body3DSW *getRigidBodyA() const { + const GodotBody3D *getRigidBodyA() const { return A; } - const Body3DSW *getRigidBodyB() const { + const GodotBody3D *getRigidBodyB() const { return B; } @@ -373,4 +319,4 @@ public: bool get_flag(Vector3::Axis p_axis, PhysicsServer3D::G6DOFJointAxisFlag p_flag) const; }; -#endif // GENERIC_6DOF_JOINT_SW_H +#endif // GODOT_GENERIC_6DOF_JOINT_3D_H diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp b/servers/physics_3d/joints/godot_hinge_joint_3d.cpp index e2bf2845fe..cf77129a30 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/godot_hinge_joint_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* hinge_joint_3d_sw.cpp */ +/* godot_hinge_joint_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library. /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -47,7 +47,7 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -#include "hinge_joint_3d_sw.h" +#include "godot_hinge_joint_3d.h" static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) { if (Math::abs(n.z) > Math_SQRT12) { @@ -67,8 +67,8 @@ static void plane_space(const Vector3 &n, Vector3 &p, Vector3 &q) { } } -HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameA, const Transform3D &frameB) : - Joint3DSW(_arr, 2) { +GodotHingeJoint3D::GodotHingeJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &frameA, const Transform3D &frameB) : + GodotJoint3D(_arr, 2) { A = rbA; B = rbB; @@ -79,28 +79,13 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D & m_rbBFrame.basis[1][2] *= real_t(-1.); m_rbBFrame.basis[2][2] *= real_t(-1.); - //start with free - m_lowerLimit = Math_PI; - m_upperLimit = -Math_PI; - - m_useLimit = false; - m_biasFactor = 0.3f; - m_relaxationFactor = 1.0f; - m_limitSoftness = 0.9f; - m_solveLimit = false; - - tau = 0.3; - - m_angularOnly = false; - m_enableAngularMotor = false; - A->add_constraint(this, 0); B->add_constraint(this, 1); } -HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, +GodotHingeJoint3D::GodotHingeJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB) : - Joint3DSW(_arr, 2) { + GodotJoint3D(_arr, 2) { A = rbA; B = rbB; @@ -135,26 +120,11 @@ HingeJoint3DSW::HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivo rbAxisB1.y, rbAxisB2.y, -axisInB.y, rbAxisB1.z, rbAxisB2.z, -axisInB.z); - //start with free - m_lowerLimit = Math_PI; - m_upperLimit = -Math_PI; - - m_useLimit = false; - m_biasFactor = 0.3f; - m_relaxationFactor = 1.0f; - m_limitSoftness = 0.9f; - m_solveLimit = false; - - tau = 0.3; - - m_angularOnly = false; - m_enableAngularMotor = false; - A->add_constraint(this, 0); B->add_constraint(this, 1); } -bool HingeJoint3DSW::setup(real_t p_step) { +bool GodotHingeJoint3D::setup(real_t p_step) { dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); @@ -179,16 +149,18 @@ bool HingeJoint3DSW::setup(real_t p_step) { plane_space(normal[0], normal[1], normal[2]); for (int i = 0; i < 3; i++) { - memnew_placement(&m_jac[i], JacobianEntry3DSW( - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - pivotAInW - A->get_transform().origin - A->get_center_of_mass(), - pivotBInW - B->get_transform().origin - B->get_center_of_mass(), - normal[i], - A->get_inv_inertia(), - A->get_inv_mass(), - B->get_inv_inertia(), - B->get_inv_mass())); + memnew_placement( + &m_jac[i], + GodotJacobianEntry3D( + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + pivotAInW - A->get_transform().origin - A->get_center_of_mass(), + pivotBInW - B->get_transform().origin - B->get_center_of_mass(), + normal[i], + A->get_inv_inertia(), + A->get_inv_mass(), + B->get_inv_inertia(), + B->get_inv_mass())); } } @@ -205,23 +177,32 @@ bool HingeJoint3DSW::setup(real_t p_step) { Vector3 jointAxis1 = A->get_transform().basis.xform(jointAxis1local); Vector3 hingeAxisWorld = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2)); - memnew_placement(&m_jacAng[0], JacobianEntry3DSW(jointAxis0, - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - A->get_inv_inertia(), - B->get_inv_inertia())); - - memnew_placement(&m_jacAng[1], JacobianEntry3DSW(jointAxis1, - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - A->get_inv_inertia(), - B->get_inv_inertia())); - - memnew_placement(&m_jacAng[2], JacobianEntry3DSW(hingeAxisWorld, - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - A->get_inv_inertia(), - B->get_inv_inertia())); + memnew_placement( + &m_jacAng[0], + GodotJacobianEntry3D( + jointAxis0, + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + A->get_inv_inertia(), + B->get_inv_inertia())); + + memnew_placement( + &m_jacAng[1], + GodotJacobianEntry3D( + jointAxis1, + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + A->get_inv_inertia(), + B->get_inv_inertia())); + + memnew_placement( + &m_jacAng[2], + GodotJacobianEntry3D( + hingeAxisWorld, + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + A->get_inv_inertia(), + B->get_inv_inertia())); // Compute limit information real_t hingeAngle = get_hinge_angle(); @@ -250,13 +231,12 @@ bool HingeJoint3DSW::setup(real_t p_step) { //Compute K = J*W*J' for hinge axis Vector3 axisA = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(2)); - m_kHinge = 1.0f / (A->compute_angular_impulse_denominator(axisA) + - B->compute_angular_impulse_denominator(axisA)); + m_kHinge = 1.0f / (A->compute_angular_impulse_denominator(axisA) + B->compute_angular_impulse_denominator(axisA)); return true; } -void HingeJoint3DSW::solve(real_t p_step) { +void GodotHingeJoint3D::solve(real_t p_step) { Vector3 pivotAInW = A->get_transform().xform(m_rbAFrame.origin); Vector3 pivotBInW = B->get_transform().xform(m_rbBFrame.origin); @@ -314,7 +294,7 @@ void HingeJoint3DSW::solve(real_t p_step) { if (len > real_t(0.00001)) { Vector3 normal = velrelOrthog.normalized(); real_t denom = A->compute_angular_impulse_denominator(normal) + - B->compute_angular_impulse_denominator(normal); + B->compute_angular_impulse_denominator(normal); // scale for mass and relaxation velrelOrthog *= (real_t(1.) / denom) * m_relaxationFactor; } @@ -325,7 +305,7 @@ void HingeJoint3DSW::solve(real_t p_step) { if (len2 > real_t(0.00001)) { Vector3 normal2 = angularError.normalized(); real_t denom2 = A->compute_angular_impulse_denominator(normal2) + - B->compute_angular_impulse_denominator(normal2); + B->compute_angular_impulse_denominator(normal2); angularError *= (real_t(1.) / denom2) * relaxation; } @@ -407,7 +387,7 @@ static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) { return (y < 0.0f) ? -angle : angle; } -real_t HingeJoint3DSW::get_hinge_angle() { +real_t GodotHingeJoint3D::get_hinge_angle() { const Vector3 refAxis0 = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(0)); const Vector3 refAxis1 = A->get_transform().basis.xform(m_rbAFrame.basis.get_axis(1)); const Vector3 swingAxis = B->get_transform().basis.xform(m_rbBFrame.basis.get_axis(1)); @@ -415,7 +395,7 @@ real_t HingeJoint3DSW::get_hinge_angle() { return atan2fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); } -void HingeJoint3DSW::set_param(PhysicsServer3D::HingeJointParam p_param, real_t p_value) { +void GodotHingeJoint3D::set_param(PhysicsServer3D::HingeJointParam p_param, real_t p_value) { switch (p_param) { case PhysicsServer3D::HINGE_JOINT_BIAS: tau = p_value; @@ -446,7 +426,7 @@ void HingeJoint3DSW::set_param(PhysicsServer3D::HingeJointParam p_param, real_t } } -real_t HingeJoint3DSW::get_param(PhysicsServer3D::HingeJointParam p_param) const { +real_t GodotHingeJoint3D::get_param(PhysicsServer3D::HingeJointParam p_param) const { switch (p_param) { case PhysicsServer3D::HINGE_JOINT_BIAS: return tau; @@ -471,7 +451,7 @@ real_t HingeJoint3DSW::get_param(PhysicsServer3D::HingeJointParam p_param) const return 0; } -void HingeJoint3DSW::set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value) { +void GodotHingeJoint3D::set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value) { switch (p_flag) { case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT: m_useLimit = p_value; @@ -484,7 +464,7 @@ void HingeJoint3DSW::set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_val } } -bool HingeJoint3DSW::get_flag(PhysicsServer3D::HingeJointFlag p_flag) const { +bool GodotHingeJoint3D::get_flag(PhysicsServer3D::HingeJointFlag p_flag) const { switch (p_flag) { case PhysicsServer3D::HINGE_JOINT_FLAG_USE_LIMIT: return m_useLimit; diff --git a/servers/physics_3d/joints/hinge_joint_3d_sw.h b/servers/physics_3d/joints/godot_hinge_joint_3d.h index 572c35266f..ff1fbe0f25 100644 --- a/servers/physics_3d/joints/hinge_joint_3d_sw.h +++ b/servers/physics_3d/joints/godot_hinge_joint_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* hinge_joint_3d_sw.h */ +/* godot_hinge_joint_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -32,15 +32,15 @@ Adapted to Godot from the Bullet library. */ -#ifndef HINGE_JOINT_SW_H -#define HINGE_JOINT_SW_H +#ifndef GODOT_HINGE_JOINT_3D_H +#define GODOT_HINGE_JOINT_3D_H -#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h" -#include "servers/physics_3d/joints_3d_sw.h" +#include "servers/physics_3d/godot_joint_3d.h" +#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -53,47 +53,47 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -class HingeJoint3DSW : public Joint3DSW { +class GodotHingeJoint3D : public GodotJoint3D { union { struct { - Body3DSW *A; - Body3DSW *B; + GodotBody3D *A; + GodotBody3D *B; }; - Body3DSW *_arr[2]; + GodotBody3D *_arr[2] = {}; }; - JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints - JacobianEntry3DSW m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor + GodotJacobianEntry3D m_jac[3]; //3 orthogonal linear constraints + GodotJacobianEntry3D m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor Transform3D m_rbAFrame; // constraint axii. Assumes z is hinge axis. Transform3D m_rbBFrame; - real_t m_motorTargetVelocity; - real_t m_maxMotorImpulse; + real_t m_motorTargetVelocity = 0.0; + real_t m_maxMotorImpulse = 0.0; - real_t m_limitSoftness; - real_t m_biasFactor; - real_t m_relaxationFactor; + real_t m_limitSoftness = 0.9; + real_t m_biasFactor = 0.3; + real_t m_relaxationFactor = 1.0; - real_t m_lowerLimit; - real_t m_upperLimit; + real_t m_lowerLimit = Math_PI; + real_t m_upperLimit = -Math_PI; - real_t m_kHinge; + real_t m_kHinge = 0.0; - real_t m_limitSign; - real_t m_correction; + real_t m_limitSign = 0.0; + real_t m_correction = 0.0; - real_t m_accLimitImpulse; + real_t m_accLimitImpulse = 0.0; - real_t tau; + real_t tau = 0.3; - bool m_useLimit; - bool m_angularOnly; - bool m_enableAngularMotor; - bool m_solveLimit; + bool m_useLimit = false; + bool m_angularOnly = false; + bool m_enableAngularMotor = false; + bool m_solveLimit = false; - real_t m_appliedImpulse; + real_t m_appliedImpulse = 0.0; public: virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_HINGE; } @@ -109,8 +109,8 @@ public: void set_flag(PhysicsServer3D::HingeJointFlag p_flag, bool p_value); bool get_flag(PhysicsServer3D::HingeJointFlag p_flag) const; - HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameA, const Transform3D &frameB); - HingeJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB); + GodotHingeJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &frameA, const Transform3D &frameB); + GodotHingeJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Vector3 &pivotInA, const Vector3 &pivotInB, const Vector3 &axisInA, const Vector3 &axisInB); }; -#endif // HINGE_JOINT_SW_H +#endif // GODOT_HINGE_JOINT_3D_H diff --git a/servers/physics_3d/joints/jacobian_entry_3d_sw.h b/servers/physics_3d/joints/godot_jacobian_entry_3d.h index 30c80db23f..90a77a9b61 100644 --- a/servers/physics_3d/joints/jacobian_entry_3d_sw.h +++ b/servers/physics_3d/joints/godot_jacobian_entry_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* jacobian_entry_3d_sw.h */ +/* godot_jacobian_entry_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -32,12 +32,12 @@ Adapted to Godot from the Bullet library. */ -#ifndef JACOBIAN_ENTRY_SW_H -#define JACOBIAN_ENTRY_SW_H +#ifndef GODOT_JACOBIAN_ENTRY_3D_H +#define GODOT_JACOBIAN_ENTRY_3D_H /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -52,11 +52,11 @@ subject to the following restrictions: #include "core/math/transform_3d.h" -class JacobianEntry3DSW { +class GodotJacobianEntry3D { public: - JacobianEntry3DSW() {} + GodotJacobianEntry3D() {} //constraint between two different rigidbodies - JacobianEntry3DSW( + GodotJacobianEntry3D( const Basis &world2A, const Basis &world2B, const Vector3 &rel_pos1, const Vector3 &rel_pos2, @@ -76,7 +76,7 @@ public: } //angular constraint between two different rigidbodies - JacobianEntry3DSW(const Vector3 &jointAxis, + GodotJacobianEntry3D(const Vector3 &jointAxis, const Basis &world2A, const Basis &world2B, const Vector3 &inertiaInvA, @@ -92,7 +92,7 @@ public: } //angular constraint between two different rigidbodies - JacobianEntry3DSW(const Vector3 &axisInA, + GodotJacobianEntry3D(const Vector3 &axisInA, const Vector3 &axisInB, const Vector3 &inertiaInvA, const Vector3 &inertiaInvB) : @@ -107,7 +107,7 @@ public: } //constraint on one rigidbody - JacobianEntry3DSW( + GodotJacobianEntry3D( const Basis &world2A, const Vector3 &rel_pos1, const Vector3 &rel_pos2, const Vector3 &jointAxis, @@ -126,16 +126,16 @@ public: real_t getDiagonal() const { return m_Adiag; } // for two constraints on the same rigidbody (for example vehicle friction) - real_t getNonDiagonal(const JacobianEntry3DSW &jacB, const real_t massInvA) const { - const JacobianEntry3DSW &jacA = *this; + real_t getNonDiagonal(const GodotJacobianEntry3D &jacB, const real_t massInvA) const { + const GodotJacobianEntry3D &jacA = *this; real_t lin = massInvA * jacA.m_linearJointAxis.dot(jacB.m_linearJointAxis); real_t ang = jacA.m_0MinvJt.dot(jacB.m_aJ); return lin + ang; } // for two constraints on sharing two same rigidbodies (for example two contact points between two rigidbodies) - real_t getNonDiagonal(const JacobianEntry3DSW &jacB, const real_t massInvA, const real_t massInvB) const { - const JacobianEntry3DSW &jacA = *this; + real_t getNonDiagonal(const GodotJacobianEntry3D &jacB, const real_t massInvA, const real_t massInvB) const { + const GodotJacobianEntry3D &jacA = *this; Vector3 lin = jacA.m_linearJointAxis * jacB.m_linearJointAxis; Vector3 ang0 = jacA.m_0MinvJt * jacB.m_aJ; Vector3 ang1 = jacA.m_1MinvJt * jacB.m_bJ; @@ -163,7 +163,7 @@ public: Vector3 m_0MinvJt; Vector3 m_1MinvJt; //Optimization: can be stored in the w/last component of one of the vectors - real_t m_Adiag; + real_t m_Adiag = 1.0; }; -#endif // JACOBIAN_ENTRY_SW_H +#endif // GODOT_JACOBIAN_ENTRY_3D_H diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.cpp b/servers/physics_3d/joints/godot_pin_joint_3d.cpp index 7a713c1161..e9e81b61a7 100644 --- a/servers/physics_3d/joints/pin_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/godot_pin_joint_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* pin_joint_3d_sw.cpp */ +/* godot_pin_joint_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library. /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -47,9 +47,9 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -#include "pin_joint_3d_sw.h" +#include "godot_pin_joint_3d.h" -bool PinJoint3DSW::setup(real_t p_step) { +bool GodotPinJoint3D::setup(real_t p_step) { dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); @@ -63,23 +63,25 @@ bool PinJoint3DSW::setup(real_t p_step) { for (int i = 0; i < 3; i++) { normal[i] = 1; - memnew_placement(&m_jac[i], JacobianEntry3DSW( - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - A->get_transform().xform(m_pivotInA) - A->get_transform().origin - A->get_center_of_mass(), - B->get_transform().xform(m_pivotInB) - B->get_transform().origin - B->get_center_of_mass(), - normal, - A->get_inv_inertia(), - A->get_inv_mass(), - B->get_inv_inertia(), - B->get_inv_mass())); + memnew_placement( + &m_jac[i], + GodotJacobianEntry3D( + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + A->get_transform().xform(m_pivotInA) - A->get_transform().origin - A->get_center_of_mass(), + B->get_transform().xform(m_pivotInB) - B->get_transform().origin - B->get_center_of_mass(), + normal, + A->get_inv_inertia(), + A->get_inv_mass(), + B->get_inv_inertia(), + B->get_inv_mass())); normal[i] = 0; } return true; } -void PinJoint3DSW::solve(real_t p_step) { +void GodotPinJoint3D::solve(real_t p_step) { Vector3 pivotAInW = A->get_transform().xform(m_pivotInA); Vector3 pivotBInW = B->get_transform().xform(m_pivotInB); @@ -137,7 +139,7 @@ void PinJoint3DSW::solve(real_t p_step) { } } -void PinJoint3DSW::set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value) { +void GodotPinJoint3D::set_param(PhysicsServer3D::PinJointParam p_param, real_t p_value) { switch (p_param) { case PhysicsServer3D::PIN_JOINT_BIAS: m_tau = p_value; @@ -151,7 +153,7 @@ void PinJoint3DSW::set_param(PhysicsServer3D::PinJointParam p_param, real_t p_va } } -real_t PinJoint3DSW::get_param(PhysicsServer3D::PinJointParam p_param) const { +real_t GodotPinJoint3D::get_param(PhysicsServer3D::PinJointParam p_param) const { switch (p_param) { case PhysicsServer3D::PIN_JOINT_BIAS: return m_tau; @@ -164,21 +166,16 @@ real_t PinJoint3DSW::get_param(PhysicsServer3D::PinJointParam p_param) const { return 0; } -PinJoint3DSW::PinJoint3DSW(Body3DSW *p_body_a, const Vector3 &p_pos_a, Body3DSW *p_body_b, const Vector3 &p_pos_b) : - Joint3DSW(_arr, 2) { +GodotPinJoint3D::GodotPinJoint3D(GodotBody3D *p_body_a, const Vector3 &p_pos_a, GodotBody3D *p_body_b, const Vector3 &p_pos_b) : + GodotJoint3D(_arr, 2) { A = p_body_a; B = p_body_b; m_pivotInA = p_pos_a; m_pivotInB = p_pos_b; - m_tau = 0.3; - m_damping = 1; - m_impulseClamp = 0; - m_appliedImpulse = 0; - A->add_constraint(this, 0); B->add_constraint(this, 1); } -PinJoint3DSW::~PinJoint3DSW() { +GodotPinJoint3D::~GodotPinJoint3D() { } diff --git a/servers/physics_3d/joints/pin_joint_3d_sw.h b/servers/physics_3d/joints/godot_pin_joint_3d.h index 09deefc5c4..17e2e6e973 100644 --- a/servers/physics_3d/joints/pin_joint_3d_sw.h +++ b/servers/physics_3d/joints/godot_pin_joint_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* pin_joint_3d_sw.h */ +/* godot_pin_joint_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -32,15 +32,15 @@ Adapted to Godot from the Bullet library. */ -#ifndef PIN_JOINT_SW_H -#define PIN_JOINT_SW_H +#ifndef GODOT_PIN_JOINT_3D_H +#define GODOT_PIN_JOINT_3D_H -#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h" -#include "servers/physics_3d/joints_3d_sw.h" +#include "servers/physics_3d/godot_joint_3d.h" +#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -53,22 +53,22 @@ subject to the following restrictions: 3. This notice may not be removed or altered from any source distribution. */ -class PinJoint3DSW : public Joint3DSW { +class GodotPinJoint3D : public GodotJoint3D { union { struct { - Body3DSW *A; - Body3DSW *B; + GodotBody3D *A; + GodotBody3D *B; }; - Body3DSW *_arr[2]; + GodotBody3D *_arr[2] = {}; }; - real_t m_tau; //bias - real_t m_damping; - real_t m_impulseClamp; - real_t m_appliedImpulse; + real_t m_tau = 0.3; //bias + real_t m_damping = 1.0; + real_t m_impulseClamp = 0.0; + real_t m_appliedImpulse = 0.0; - JacobianEntry3DSW m_jac[3]; //3 orthogonal linear constraints + GodotJacobianEntry3D m_jac[3] = {}; //3 orthogonal linear constraints Vector3 m_pivotInA; Vector3 m_pivotInB; @@ -88,8 +88,8 @@ public: Vector3 get_position_a() { return m_pivotInA; } Vector3 get_position_b() { return m_pivotInB; } - PinJoint3DSW(Body3DSW *p_body_a, const Vector3 &p_pos_a, Body3DSW *p_body_b, const Vector3 &p_pos_b); - ~PinJoint3DSW(); + GodotPinJoint3D(GodotBody3D *p_body_a, const Vector3 &p_pos_a, GodotBody3D *p_body_b, const Vector3 &p_pos_b); + ~GodotPinJoint3D(); }; -#endif // PIN_JOINT_SW_H +#endif // GODOT_PIN_JOINT_3D_H diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.cpp b/servers/physics_3d/joints/godot_slider_joint_3d.cpp index 9f01196c30..1f463ad24c 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.cpp +++ b/servers/physics_3d/joints/godot_slider_joint_3d.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* slider_joint_3d_sw.cpp */ +/* godot_slider_joint_3d.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -34,7 +34,7 @@ Adapted to Godot from the Bullet library. /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -53,7 +53,7 @@ April 04, 2008 */ -#include "slider_joint_3d_sw.h" +#include "godot_slider_joint_3d.h" //----------------------------------------------------------------------------- @@ -72,47 +72,12 @@ static _FORCE_INLINE_ real_t atan2fast(real_t y, real_t x) { return (y < 0.0f) ? -angle : angle; } -void SliderJoint3DSW::initParams() { - m_lowerLinLimit = real_t(1.0); - m_upperLinLimit = real_t(-1.0); - m_lowerAngLimit = real_t(0.); - m_upperAngLimit = real_t(0.); - m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; - m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; - m_dampingDirLin = real_t(0.); - m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; - m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; - m_dampingDirAng = real_t(0.); - m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; - m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; - m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING; - m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; - m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; - m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING; - m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; - m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; - m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING; - m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; - m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; - m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING; - - m_poweredLinMotor = false; - m_targetLinMotorVelocity = real_t(0.); - m_maxLinMotorForce = real_t(0.); - m_accumulatedLinMotorImpulse = real_t(0.0); - - m_poweredAngMotor = false; - m_targetAngMotorVelocity = real_t(0.); - m_maxAngMotorForce = real_t(0.); - m_accumulatedAngMotorImpulse = real_t(0.0); -} // SliderJointSW::initParams() - //----------------------------------------------------------------------------- //----------------------------------------------------------------------------- -SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : - Joint3DSW(_arr, 2), +GodotSliderJoint3D::GodotSliderJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &frameInA, const Transform3D &frameInB) : + GodotJoint3D(_arr, 2), m_frameInA(frameInA), m_frameInB(frameInB) { A = rbA; @@ -120,13 +85,11 @@ SliderJoint3DSW::SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D A->add_constraint(this, 0); B->add_constraint(this, 1); - - initParams(); -} // SliderJointSW::SliderJointSW() +} //----------------------------------------------------------------------------- -bool SliderJoint3DSW::setup(real_t p_step) { +bool GodotSliderJoint3D::setup(real_t p_step) { dynamic_A = (A->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); dynamic_B = (B->get_mode() > PhysicsServer3D::BODY_MODE_KINEMATIC); @@ -149,16 +112,18 @@ bool SliderJoint3DSW::setup(real_t p_step) { //linear part for (i = 0; i < 3; i++) { normalWorld = m_calculatedTransformA.basis.get_axis(i); - memnew_placement(&m_jacLin[i], JacobianEntry3DSW( - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - m_relPosA - A->get_center_of_mass(), - m_relPosB - B->get_center_of_mass(), - normalWorld, - A->get_inv_inertia(), - A->get_inv_mass(), - B->get_inv_inertia(), - B->get_inv_mass())); + memnew_placement( + &m_jacLin[i], + GodotJacobianEntry3D( + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + m_relPosA - A->get_center_of_mass(), + m_relPosB - B->get_center_of_mass(), + normalWorld, + A->get_inv_inertia(), + A->get_inv_mass(), + B->get_inv_inertia(), + B->get_inv_mass())); m_jacLinDiagABInv[i] = real_t(1.) / m_jacLin[i].getDiagonal(); m_depth[i] = m_delta.dot(normalWorld); } @@ -166,12 +131,14 @@ bool SliderJoint3DSW::setup(real_t p_step) { // angular part for (i = 0; i < 3; i++) { normalWorld = m_calculatedTransformA.basis.get_axis(i); - memnew_placement(&m_jacAng[i], JacobianEntry3DSW( - normalWorld, - A->get_principal_inertia_axes().transposed(), - B->get_principal_inertia_axes().transposed(), - A->get_inv_inertia(), - B->get_inv_inertia())); + memnew_placement( + &m_jacAng[i], + GodotJacobianEntry3D( + normalWorld, + A->get_principal_inertia_axes().transposed(), + B->get_principal_inertia_axes().transposed(), + A->get_inv_inertia(), + B->get_inv_inertia())); } testAngLimits(); Vector3 axisA = m_calculatedTransformA.basis.get_axis(0); @@ -181,11 +148,11 @@ bool SliderJoint3DSW::setup(real_t p_step) { m_accumulatedAngMotorImpulse = real_t(0.0); return true; -} // SliderJointSW::buildJacobianInt() +} //----------------------------------------------------------------------------- -void SliderJoint3DSW::solve(real_t p_step) { +void GodotSliderJoint3D::solve(real_t p_step) { int i; // linear Vector3 velA = A->get_velocity_in_local_point(m_relPosA); @@ -321,13 +288,11 @@ void SliderJoint3DSW::solve(real_t p_step) { } } } -} // SliderJointSW::solveConstraint() - -//----------------------------------------------------------------------------- +} //----------------------------------------------------------------------------- -void SliderJoint3DSW::calculateTransforms() { +void GodotSliderJoint3D::calculateTransforms() { m_calculatedTransformA = A->get_transform() * m_frameInA; m_calculatedTransformB = B->get_transform() * m_frameInB; m_realPivotAInW = m_calculatedTransformA.origin; @@ -342,11 +307,11 @@ void SliderJoint3DSW::calculateTransforms() { normalWorld = m_calculatedTransformA.basis.get_axis(i); m_depth[i] = m_delta.dot(normalWorld); } -} // SliderJointSW::calculateTransforms() +} //----------------------------------------------------------------------------- -void SliderJoint3DSW::testLinLimits() { +void GodotSliderJoint3D::testLinLimits() { m_solveLinLim = false; m_linPos = m_depth[0]; if (m_lowerLinLimit <= m_upperLinLimit) { @@ -362,11 +327,11 @@ void SliderJoint3DSW::testLinLimits() { } else { m_depth[0] = real_t(0.); } -} // SliderJointSW::testLinLimits() +} //----------------------------------------------------------------------------- -void SliderJoint3DSW::testAngLimits() { +void GodotSliderJoint3D::testAngLimits() { m_angDepth = real_t(0.); m_solveAngLim = false; if (m_lowerAngLimit <= m_upperAngLimit) { @@ -382,26 +347,26 @@ void SliderJoint3DSW::testAngLimits() { m_solveAngLim = true; } } -} // SliderJointSW::testAngLimits() +} //----------------------------------------------------------------------------- -Vector3 SliderJoint3DSW::getAncorInA() { +Vector3 GodotSliderJoint3D::getAncorInA() { Vector3 ancorInA; ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * real_t(0.5) * m_sliderAxis; ancorInA = A->get_transform().inverse().xform(ancorInA); return ancorInA; -} // SliderJointSW::getAncorInA() +} //----------------------------------------------------------------------------- -Vector3 SliderJoint3DSW::getAncorInB() { +Vector3 GodotSliderJoint3D::getAncorInB() { Vector3 ancorInB; ancorInB = m_frameInB.origin; return ancorInB; -} // SliderJointSW::getAncorInB(); +} -void SliderJoint3DSW::set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value) { +void GodotSliderJoint3D::set_param(PhysicsServer3D::SliderJointParam p_param, real_t p_value) { switch (p_param) { case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: m_upperLinLimit = p_value; @@ -476,7 +441,7 @@ void SliderJoint3DSW::set_param(PhysicsServer3D::SliderJointParam p_param, real_ } } -real_t SliderJoint3DSW::get_param(PhysicsServer3D::SliderJointParam p_param) const { +real_t GodotSliderJoint3D::get_param(PhysicsServer3D::SliderJointParam p_param) const { switch (p_param) { case PhysicsServer3D::SLIDER_JOINT_LINEAR_LIMIT_UPPER: return m_upperLinLimit; diff --git a/servers/physics_3d/joints/slider_joint_3d_sw.h b/servers/physics_3d/joints/godot_slider_joint_3d.h index f09476f570..9baaf1fa40 100644 --- a/servers/physics_3d/joints/slider_joint_3d_sw.h +++ b/servers/physics_3d/joints/godot_slider_joint_3d.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* slider_joint_3d_sw.h */ +/* godot_slider_joint_3d.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -32,15 +32,15 @@ Adapted to Godot from the Bullet library. */ -#ifndef SLIDER_JOINT_SW_H -#define SLIDER_JOINT_SW_H +#ifndef GODOT_SLIDER_JOINT_3D_H +#define GODOT_SLIDER_JOINT_3D_H -#include "servers/physics_3d/joints/jacobian_entry_3d_sw.h" -#include "servers/physics_3d/joints_3d_sw.h" +#include "servers/physics_3d/godot_joint_3d.h" +#include "servers/physics_3d/joints/godot_jacobian_entry_3d.h" /* Bullet Continuous Collision Detection and Physics Library -Copyright (c) 2003-2006 Erwin Coumans https://bulletphysics.org +Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages arising from the use of this software. @@ -65,61 +65,61 @@ April 04, 2008 //----------------------------------------------------------------------------- -class SliderJoint3DSW : public Joint3DSW { +class GodotSliderJoint3D : public GodotJoint3D { protected: union { struct { - Body3DSW *A; - Body3DSW *B; + GodotBody3D *A; + GodotBody3D *B; }; - Body3DSW *_arr[2]; + GodotBody3D *_arr[2] = { nullptr, nullptr }; }; Transform3D m_frameInA; Transform3D m_frameInB; // linear limits - real_t m_lowerLinLimit; - real_t m_upperLinLimit; + real_t m_lowerLinLimit = 1.0; + real_t m_upperLinLimit = -1.0; // angular limits - real_t m_lowerAngLimit; - real_t m_upperAngLimit; + real_t m_lowerAngLimit = 0.0; + real_t m_upperAngLimit = 0.0; // softness, restitution and damping for different cases // DirLin - moving inside linear limits // LimLin - hitting linear limit // DirAng - moving inside angular limits // LimAng - hitting angular limit // OrthoLin, OrthoAng - against constraint axis - real_t m_softnessDirLin; - real_t m_restitutionDirLin; - real_t m_dampingDirLin; - real_t m_softnessDirAng; - real_t m_restitutionDirAng; - real_t m_dampingDirAng; - real_t m_softnessLimLin; - real_t m_restitutionLimLin; - real_t m_dampingLimLin; - real_t m_softnessLimAng; - real_t m_restitutionLimAng; - real_t m_dampingLimAng; - real_t m_softnessOrthoLin; - real_t m_restitutionOrthoLin; - real_t m_dampingOrthoLin; - real_t m_softnessOrthoAng; - real_t m_restitutionOrthoAng; - real_t m_dampingOrthoAng; + real_t m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; + real_t m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; + real_t m_dampingDirLin = 0.0; + real_t m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; + real_t m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; + real_t m_dampingDirAng = 0.0; + real_t m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; + real_t m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; + real_t m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING; + real_t m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; + real_t m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; + real_t m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING; + real_t m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; + real_t m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; + real_t m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING; + real_t m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; + real_t m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; + real_t m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING; // for interlal use - bool m_solveLinLim; - bool m_solveAngLim; + bool m_solveLinLim = false; + bool m_solveAngLim = false; - JacobianEntry3DSW m_jacLin[3]; - real_t m_jacLinDiagABInv[3]; + GodotJacobianEntry3D m_jacLin[3] = {}; + real_t m_jacLinDiagABInv[3] = {}; - JacobianEntry3DSW m_jacAng[3]; + GodotJacobianEntry3D m_jacAng[3] = {}; - real_t m_timeStep; + real_t m_timeStep = 0.0; Transform3D m_calculatedTransformA; Transform3D m_calculatedTransformB; @@ -132,33 +132,30 @@ protected: Vector3 m_relPosA; Vector3 m_relPosB; - real_t m_linPos; + real_t m_linPos = 0.0; - real_t m_angDepth; - real_t m_kAngle; + real_t m_angDepth = 0.0; + real_t m_kAngle = 0.0; - bool m_poweredLinMotor; - real_t m_targetLinMotorVelocity; - real_t m_maxLinMotorForce; - real_t m_accumulatedLinMotorImpulse; + bool m_poweredLinMotor = false; + real_t m_targetLinMotorVelocity = 0.0; + real_t m_maxLinMotorForce = 0.0; + real_t m_accumulatedLinMotorImpulse = 0.0; - bool m_poweredAngMotor; - real_t m_targetAngMotorVelocity; - real_t m_maxAngMotorForce; - real_t m_accumulatedAngMotorImpulse; - - //------------------------ - void initParams(); + bool m_poweredAngMotor = false; + real_t m_targetAngMotorVelocity = 0.0; + real_t m_maxAngMotorForce = 0.0; + real_t m_accumulatedAngMotorImpulse = 0.0; public: // constructors - SliderJoint3DSW(Body3DSW *rbA, Body3DSW *rbB, const Transform3D &frameInA, const Transform3D &frameInB); + GodotSliderJoint3D(GodotBody3D *rbA, GodotBody3D *rbB, const Transform3D &frameInA, const Transform3D &frameInB); //SliderJointSW(); // overrides // access - const Body3DSW *getRigidBodyA() const { return A; } - const Body3DSW *getRigidBodyB() const { return B; } + const GodotBody3D *getRigidBodyA() const { return A; } + const GodotBody3D *getRigidBodyB() const { return B; } const Transform3D &getCalculatedTransformA() const { return m_calculatedTransformA; } const Transform3D &getCalculatedTransformB() const { return m_calculatedTransformB; } const Transform3D &getFrameOffsetA() const { return m_frameInA; } @@ -246,4 +243,4 @@ public: virtual PhysicsServer3D::JointType get_type() const override { return PhysicsServer3D::JOINT_TYPE_SLIDER; } }; -#endif // SLIDER_JOINT_SW_H +#endif // GODOT_SLIDER_JOINT_3D_H diff --git a/servers/physics_3d/physics_server_3d_sw.cpp b/servers/physics_3d/physics_server_3d_sw.cpp deleted file mode 100644 index a214e80c6c..0000000000 --- a/servers/physics_3d/physics_server_3d_sw.cpp +++ /dev/null @@ -1,1747 +0,0 @@ -/*************************************************************************/ -/* physics_server_3d_sw.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "physics_server_3d_sw.h" - -#include "body_direct_state_3d_sw.h" -#include "broad_phase_3d_bvh.h" -#include "core/debugger/engine_debugger.h" -#include "core/os/os.h" -#include "joints/cone_twist_joint_3d_sw.h" -#include "joints/generic_6dof_joint_3d_sw.h" -#include "joints/hinge_joint_3d_sw.h" -#include "joints/pin_joint_3d_sw.h" -#include "joints/slider_joint_3d_sw.h" - -#define FLUSH_QUERY_CHECK(m_object) \ - ERR_FAIL_COND_MSG(m_object->get_space() && flushing_queries, "Can't change this state while flushing queries. Use call_deferred() or set_deferred() to change monitoring state instead."); - -RID PhysicsServer3DSW::plane_shape_create() { - Shape3DSW *shape = memnew(PlaneShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::separation_ray_shape_create() { - Shape3DSW *shape = memnew(SeparationRayShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::sphere_shape_create() { - Shape3DSW *shape = memnew(SphereShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::box_shape_create() { - Shape3DSW *shape = memnew(BoxShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::capsule_shape_create() { - Shape3DSW *shape = memnew(CapsuleShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::cylinder_shape_create() { - Shape3DSW *shape = memnew(CylinderShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::convex_polygon_shape_create() { - Shape3DSW *shape = memnew(ConvexPolygonShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::concave_polygon_shape_create() { - Shape3DSW *shape = memnew(ConcavePolygonShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::heightmap_shape_create() { - Shape3DSW *shape = memnew(HeightMapShape3DSW); - RID rid = shape_owner.make_rid(shape); - shape->set_self(rid); - return rid; -} -RID PhysicsServer3DSW::custom_shape_create() { - ERR_FAIL_V(RID()); -} - -void PhysicsServer3DSW::shape_set_data(RID p_shape, const Variant &p_data) { - Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - shape->set_data(p_data); -}; - -void PhysicsServer3DSW::shape_set_custom_solver_bias(RID p_shape, real_t p_bias) { - Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - shape->set_custom_bias(p_bias); -} - -PhysicsServer3D::ShapeType PhysicsServer3DSW::shape_get_type(RID p_shape) const { - const Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND_V(!shape, SHAPE_CUSTOM); - return shape->get_type(); -}; - -Variant PhysicsServer3DSW::shape_get_data(RID p_shape) const { - const Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND_V(!shape, Variant()); - ERR_FAIL_COND_V(!shape->is_configured(), Variant()); - return shape->get_data(); -}; - -void PhysicsServer3DSW::shape_set_margin(RID p_shape, real_t p_margin) { -} - -real_t PhysicsServer3DSW::shape_get_margin(RID p_shape) const { - return 0.0; -} - -real_t PhysicsServer3DSW::shape_get_custom_solver_bias(RID p_shape) const { - const Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND_V(!shape, 0); - return shape->get_custom_bias(); -} - -RID PhysicsServer3DSW::space_create() { - Space3DSW *space = memnew(Space3DSW); - RID id = space_owner.make_rid(space); - space->set_self(id); - RID area_id = area_create(); - Area3DSW *area = area_owner.getornull(area_id); - ERR_FAIL_COND_V(!area, RID()); - space->set_default_area(area); - area->set_space(space); - area->set_priority(-1); - RID sgb = body_create(); - body_set_space(sgb, id); - body_set_mode(sgb, BODY_MODE_STATIC); - space->set_static_global_body(sgb); - - return id; -}; - -void PhysicsServer3DSW::space_set_active(RID p_space, bool p_active) { - Space3DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - if (p_active) { - active_spaces.insert(space); - } else { - active_spaces.erase(space); - } -} - -bool PhysicsServer3DSW::space_is_active(RID p_space) const { - const Space3DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, false); - - return active_spaces.has(space); -} - -void PhysicsServer3DSW::space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) { - Space3DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - - space->set_param(p_param, p_value); -} - -real_t PhysicsServer3DSW::space_get_param(RID p_space, SpaceParameter p_param) const { - const Space3DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, 0); - return space->get_param(p_param); -} - -PhysicsDirectSpaceState3D *PhysicsServer3DSW::space_get_direct_state(RID p_space) { - Space3DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, nullptr); - ERR_FAIL_COND_V_MSG((using_threads && !doing_sync) || space->is_locked(), nullptr, "Space state is inaccessible right now, wait for iteration or physics process notification."); - - return space->get_direct_state(); -} - -void PhysicsServer3DSW::space_set_debug_contacts(RID p_space, int p_max_contacts) { - Space3DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - space->set_debug_contacts(p_max_contacts); -} - -Vector<Vector3> PhysicsServer3DSW::space_get_contacts(RID p_space) const { - Space3DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, Vector<Vector3>()); - return space->get_debug_contacts(); -} - -int PhysicsServer3DSW::space_get_contact_count(RID p_space) const { - Space3DSW *space = space_owner.getornull(p_space); - ERR_FAIL_COND_V(!space, 0); - return space->get_debug_contact_count(); -} - -RID PhysicsServer3DSW::area_create() { - Area3DSW *area = memnew(Area3DSW); - RID rid = area_owner.make_rid(area); - area->set_self(rid); - return rid; -}; - -void PhysicsServer3DSW::area_set_space(RID p_area, RID p_space) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - Space3DSW *space = nullptr; - if (p_space.is_valid()) { - space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - } - - if (area->get_space() == space) { - return; //pointless - } - - area->clear_constraints(); - area->set_space(space); -}; - -RID PhysicsServer3DSW::area_get_space(RID p_area) const { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, RID()); - - Space3DSW *space = area->get_space(); - if (!space) { - return RID(); - } - return space->get_self(); -}; - -void PhysicsServer3DSW::area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_space_override_mode(p_mode); -} - -PhysicsServer3D::AreaSpaceOverrideMode PhysicsServer3DSW::area_get_space_override_mode(RID p_area) const { - const Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, AREA_SPACE_OVERRIDE_DISABLED); - - return area->get_space_override_mode(); -} - -void PhysicsServer3DSW::area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform, bool p_disabled) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - - area->add_shape(shape, p_transform, p_disabled); -} - -void PhysicsServer3DSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - ERR_FAIL_COND(!shape->is_configured()); - - area->set_shape(p_shape_idx, shape); -} - -void PhysicsServer3DSW::area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_shape_transform(p_shape_idx, p_transform); -} - -int PhysicsServer3DSW::area_get_shape_count(RID p_area) const { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, -1); - - return area->get_shape_count(); -} - -RID PhysicsServer3DSW::area_get_shape(RID p_area, int p_shape_idx) const { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, RID()); - - Shape3DSW *shape = area->get_shape(p_shape_idx); - ERR_FAIL_COND_V(!shape, RID()); - - return shape->get_self(); -} - -Transform3D PhysicsServer3DSW::area_get_shape_transform(RID p_area, int p_shape_idx) const { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform3D()); - - return area->get_shape_transform(p_shape_idx); -} - -void PhysicsServer3DSW::area_remove_shape(RID p_area, int p_shape_idx) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->remove_shape(p_shape_idx); -} - -void PhysicsServer3DSW::area_clear_shapes(RID p_area) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - while (area->get_shape_count()) { - area->remove_shape(0); - } -} - -void PhysicsServer3DSW::area_set_shape_disabled(RID p_area, int p_shape_idx, bool p_disabled) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - ERR_FAIL_INDEX(p_shape_idx, area->get_shape_count()); - FLUSH_QUERY_CHECK(area); - area->set_shape_disabled(p_shape_idx, p_disabled); -} - -void PhysicsServer3DSW::area_attach_object_instance_id(RID p_area, ObjectID p_id) { - if (space_owner.owns(p_area)) { - Space3DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - area->set_instance_id(p_id); -} - -ObjectID PhysicsServer3DSW::area_get_object_instance_id(RID p_area) const { - if (space_owner.owns(p_area)) { - Space3DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, ObjectID()); - return area->get_instance_id(); -} - -void PhysicsServer3DSW::area_set_param(RID p_area, AreaParameter p_param, const Variant &p_value) { - if (space_owner.owns(p_area)) { - Space3DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - area->set_param(p_param, p_value); -}; - -void PhysicsServer3DSW::area_set_transform(RID p_area, const Transform3D &p_transform) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - area->set_transform(p_transform); -}; - -Variant PhysicsServer3DSW::area_get_param(RID p_area, AreaParameter p_param) const { - if (space_owner.owns(p_area)) { - Space3DSW *space = space_owner.getornull(p_area); - p_area = space->get_default_area()->get_self(); - } - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Variant()); - - return area->get_param(p_param); -}; - -Transform3D PhysicsServer3DSW::area_get_transform(RID p_area) const { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND_V(!area, Transform3D()); - - return area->get_transform(); -}; - -void PhysicsServer3DSW::area_set_collision_layer(RID p_area, uint32_t p_layer) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_collision_layer(p_layer); -} - -void PhysicsServer3DSW::area_set_collision_mask(RID p_area, uint32_t p_mask) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_collision_mask(p_mask); -} - -void PhysicsServer3DSW::area_set_monitorable(RID p_area, bool p_monitorable) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - FLUSH_QUERY_CHECK(area); - - area->set_monitorable(p_monitorable); -} - -void PhysicsServer3DSW::area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method); -} - -void PhysicsServer3DSW::area_set_ray_pickable(RID p_area, bool p_enable) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_ray_pickable(p_enable); -} - -void PhysicsServer3DSW::area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) { - Area3DSW *area = area_owner.getornull(p_area); - ERR_FAIL_COND(!area); - - area->set_area_monitor_callback(p_receiver ? p_receiver->get_instance_id() : ObjectID(), p_method); -} - -/* BODY API */ - -RID PhysicsServer3DSW::body_create() { - Body3DSW *body = memnew(Body3DSW); - RID rid = body_owner.make_rid(body); - body->set_self(rid); - return rid; -}; - -void PhysicsServer3DSW::body_set_space(RID p_body, RID p_space) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - Space3DSW *space = nullptr; - if (p_space.is_valid()) { - space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - } - - if (body->get_space() == space) { - return; //pointless - } - - body->clear_constraint_map(); - body->set_space(space); -}; - -RID PhysicsServer3DSW::body_get_space(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, RID()); - - Space3DSW *space = body->get_space(); - if (!space) { - return RID(); - } - return space->get_self(); -}; - -void PhysicsServer3DSW::body_set_mode(RID p_body, BodyMode p_mode) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_mode(p_mode); -}; - -PhysicsServer3D::BodyMode PhysicsServer3DSW::body_get_mode(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, BODY_MODE_STATIC); - - return body->get_mode(); -}; - -void PhysicsServer3DSW::body_add_shape(RID p_body, RID p_shape, const Transform3D &p_transform, bool p_disabled) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - - body->add_shape(shape, p_transform, p_disabled); -} - -void PhysicsServer3DSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - Shape3DSW *shape = shape_owner.getornull(p_shape); - ERR_FAIL_COND(!shape); - ERR_FAIL_COND(!shape->is_configured()); - - body->set_shape(p_shape_idx, shape); -} -void PhysicsServer3DSW::body_set_shape_transform(RID p_body, int p_shape_idx, const Transform3D &p_transform) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_shape_transform(p_shape_idx, p_transform); -} - -int PhysicsServer3DSW::body_get_shape_count(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, -1); - - return body->get_shape_count(); -} - -RID PhysicsServer3DSW::body_get_shape(RID p_body, int p_shape_idx) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, RID()); - - Shape3DSW *shape = body->get_shape(p_shape_idx); - ERR_FAIL_COND_V(!shape, RID()); - - return shape->get_self(); -} - -void PhysicsServer3DSW::body_set_shape_disabled(RID p_body, int p_shape_idx, bool p_disabled) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - ERR_FAIL_INDEX(p_shape_idx, body->get_shape_count()); - FLUSH_QUERY_CHECK(body); - - body->set_shape_disabled(p_shape_idx, p_disabled); -} - -Transform3D PhysicsServer3DSW::body_get_shape_transform(RID p_body, int p_shape_idx) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Transform3D()); - - return body->get_shape_transform(p_shape_idx); -} - -void PhysicsServer3DSW::body_remove_shape(RID p_body, int p_shape_idx) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->remove_shape(p_shape_idx); -} - -void PhysicsServer3DSW::body_clear_shapes(RID p_body) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - while (body->get_shape_count()) { - body->remove_shape(0); - } -} - -void PhysicsServer3DSW::body_set_enable_continuous_collision_detection(RID p_body, bool p_enable) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_continuous_collision_detection(p_enable); -} - -bool PhysicsServer3DSW::body_is_continuous_collision_detection_enabled(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, false); - - return body->is_continuous_collision_detection_enabled(); -} - -void PhysicsServer3DSW::body_set_collision_layer(RID p_body, uint32_t p_layer) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_collision_layer(p_layer); - body->wakeup(); -} - -uint32_t PhysicsServer3DSW::body_get_collision_layer(RID p_body) const { - const Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_collision_layer(); -} - -void PhysicsServer3DSW::body_set_collision_mask(RID p_body, uint32_t p_mask) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_collision_mask(p_mask); - body->wakeup(); -} - -uint32_t PhysicsServer3DSW::body_get_collision_mask(RID p_body) const { - const Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_collision_mask(); -} - -void PhysicsServer3DSW::body_attach_object_instance_id(RID p_body, ObjectID p_id) { - Body3DSW *body = body_owner.getornull(p_body); - if (body) { - body->set_instance_id(p_id); - return; - } - - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - if (soft_body) { - soft_body->set_instance_id(p_id); - return; - } - - ERR_FAIL_MSG("Invalid ID."); -}; - -ObjectID PhysicsServer3DSW::body_get_object_instance_id(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, ObjectID()); - - return body->get_instance_id(); -}; - -void PhysicsServer3DSW::body_set_user_flags(RID p_body, uint32_t p_flags) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); -}; - -uint32_t PhysicsServer3DSW::body_get_user_flags(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return 0; -}; - -void PhysicsServer3DSW::body_set_param(RID p_body, BodyParameter p_param, real_t p_value) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_param(p_param, p_value); -}; - -real_t PhysicsServer3DSW::body_get_param(RID p_body, BodyParameter p_param) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - - return body->get_param(p_param); -}; - -void PhysicsServer3DSW::body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_state(p_state, p_variant); -}; - -Variant PhysicsServer3DSW::body_get_state(RID p_body, BodyState p_state) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Variant()); - - return body->get_state(p_state); -}; - -void PhysicsServer3DSW::body_set_applied_force(RID p_body, const Vector3 &p_force) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_applied_force(p_force); - body->wakeup(); -}; - -Vector3 PhysicsServer3DSW::body_get_applied_force(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Vector3()); - return body->get_applied_force(); -}; - -void PhysicsServer3DSW::body_set_applied_torque(RID p_body, const Vector3 &p_torque) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_applied_torque(p_torque); - body->wakeup(); -}; - -Vector3 PhysicsServer3DSW::body_get_applied_torque(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, Vector3()); - - return body->get_applied_torque(); -}; - -void PhysicsServer3DSW::body_add_central_force(RID p_body, const Vector3 &p_force) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->add_central_force(p_force); - body->wakeup(); -} - -void PhysicsServer3DSW::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_position) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->add_force(p_force, p_position); - body->wakeup(); -}; - -void PhysicsServer3DSW::body_add_torque(RID p_body, const Vector3 &p_torque) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->add_torque(p_torque); - body->wakeup(); -}; - -void PhysicsServer3DSW::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - _update_shapes(); - - body->apply_central_impulse(p_impulse); - body->wakeup(); -} - -void PhysicsServer3DSW::body_apply_impulse(RID p_body, const Vector3 &p_impulse, const Vector3 &p_position) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - _update_shapes(); - - body->apply_impulse(p_impulse, p_position); - body->wakeup(); -}; - -void PhysicsServer3DSW::body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - _update_shapes(); - - body->apply_torque_impulse(p_impulse); - body->wakeup(); -}; - -void PhysicsServer3DSW::body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - _update_shapes(); - - Vector3 v = body->get_linear_velocity(); - Vector3 axis = p_axis_velocity.normalized(); - v -= axis * axis.dot(v); - v += p_axis_velocity; - body->set_linear_velocity(v); - body->wakeup(); -}; - -void PhysicsServer3DSW::body_set_axis_lock(RID p_body, BodyAxis p_axis, bool p_lock) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_axis_lock(p_axis, p_lock); - body->wakeup(); -} - -bool PhysicsServer3DSW::body_is_axis_locked(RID p_body, BodyAxis p_axis) const { - const Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - return body->is_axis_locked(p_axis); -} - -void PhysicsServer3DSW::body_add_collision_exception(RID p_body, RID p_body_b) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->add_exception(p_body_b); - body->wakeup(); -}; - -void PhysicsServer3DSW::body_remove_collision_exception(RID p_body, RID p_body_b) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->remove_exception(p_body_b); - body->wakeup(); -}; - -void PhysicsServer3DSW::body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - for (int i = 0; i < body->get_exceptions().size(); i++) { - p_exceptions->push_back(body->get_exceptions()[i]); - } -}; - -void PhysicsServer3DSW::body_set_contacts_reported_depth_threshold(RID p_body, real_t p_threshold) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); -}; - -real_t PhysicsServer3DSW::body_get_contacts_reported_depth_threshold(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, 0); - return 0; -}; - -void PhysicsServer3DSW::body_set_omit_force_integration(RID p_body, bool p_omit) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - - body->set_omit_force_integration(p_omit); -}; - -bool PhysicsServer3DSW::body_is_omitting_force_integration(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, false); - return body->get_omit_force_integration(); -}; - -void PhysicsServer3DSW::body_set_max_contacts_reported(RID p_body, int p_contacts) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_max_contacts_reported(p_contacts); -} - -int PhysicsServer3DSW::body_get_max_contacts_reported(RID p_body) const { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, -1); - return body->get_max_contacts_reported(); -} - -void PhysicsServer3DSW::body_set_state_sync_callback(RID p_body, void *p_instance, BodyStateCallback p_callback) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_state_sync_callback(p_instance, p_callback); -} - -void PhysicsServer3DSW::body_set_force_integration_callback(RID p_body, const Callable &p_callable, const Variant &p_udata) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_force_integration_callback(p_callable, p_udata); -} - -void PhysicsServer3DSW::body_set_ray_pickable(RID p_body, bool p_enable) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND(!body); - body->set_ray_pickable(p_enable); -} - -bool PhysicsServer3DSW::body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, MotionResult *r_result, bool p_collide_separation_ray, const Set<RID> &p_exclude) { - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_COND_V(!body, false); - ERR_FAIL_COND_V(!body->get_space(), false); - ERR_FAIL_COND_V(body->get_space()->is_locked(), false); - - _update_shapes(); - - return body->get_space()->test_body_motion(body, p_from, p_motion, p_margin, r_result, p_collide_separation_ray, p_exclude); -} - -PhysicsDirectBodyState3D *PhysicsServer3DSW::body_get_direct_state(RID p_body) { - ERR_FAIL_COND_V_MSG((using_threads && !doing_sync), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); - - Body3DSW *body = body_owner.getornull(p_body); - ERR_FAIL_NULL_V(body, nullptr); - - ERR_FAIL_NULL_V(body->get_space(), nullptr); - ERR_FAIL_COND_V_MSG(body->get_space()->is_locked(), nullptr, "Body state is inaccessible right now, wait for iteration or physics process notification."); - - return body->get_direct_state(); -} - -/* SOFT BODY */ - -RID PhysicsServer3DSW::soft_body_create() { - SoftBody3DSW *soft_body = memnew(SoftBody3DSW); - RID rid = soft_body_owner.make_rid(soft_body); - soft_body->set_self(rid); - return rid; -} - -void PhysicsServer3DSW::soft_body_update_rendering_server(RID p_body, RenderingServerHandler *p_rendering_server_handler) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->update_rendering_server(p_rendering_server_handler); -} - -void PhysicsServer3DSW::soft_body_set_space(RID p_body, RID p_space) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - Space3DSW *space = nullptr; - if (p_space.is_valid()) { - space = space_owner.getornull(p_space); - ERR_FAIL_COND(!space); - } - - if (soft_body->get_space() == space) { - return; - } - - soft_body->set_space(space); -} - -RID PhysicsServer3DSW::soft_body_get_space(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, RID()); - - Space3DSW *space = soft_body->get_space(); - if (!space) { - return RID(); - } - return space->get_self(); -} - -void PhysicsServer3DSW::soft_body_set_collision_layer(RID p_body, uint32_t p_layer) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_collision_layer(p_layer); -} - -uint32_t PhysicsServer3DSW::soft_body_get_collision_layer(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, 0); - - return soft_body->get_collision_layer(); -} - -void PhysicsServer3DSW::soft_body_set_collision_mask(RID p_body, uint32_t p_mask) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_collision_mask(p_mask); -} - -uint32_t PhysicsServer3DSW::soft_body_get_collision_mask(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, 0); - - return soft_body->get_collision_mask(); -} - -void PhysicsServer3DSW::soft_body_add_collision_exception(RID p_body, RID p_body_b) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->add_exception(p_body_b); -} - -void PhysicsServer3DSW::soft_body_remove_collision_exception(RID p_body, RID p_body_b) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->remove_exception(p_body_b); -} - -void PhysicsServer3DSW::soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - for (int i = 0; i < soft_body->get_exceptions().size(); i++) { - p_exceptions->push_back(soft_body->get_exceptions()[i]); - } -} - -void PhysicsServer3DSW::soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_state(p_state, p_variant); -} - -Variant PhysicsServer3DSW::soft_body_get_state(RID p_body, BodyState p_state) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, Variant()); - - return soft_body->get_state(p_state); -} - -void PhysicsServer3DSW::soft_body_set_transform(RID p_body, const Transform3D &p_transform) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_state(BODY_STATE_TRANSFORM, p_transform); -} - -void PhysicsServer3DSW::soft_body_set_ray_pickable(RID p_body, bool p_enable) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_ray_pickable(p_enable); -} - -void PhysicsServer3DSW::soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_iteration_count(p_simulation_precision); -} - -int PhysicsServer3DSW::soft_body_get_simulation_precision(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, 0.f); - - return soft_body->get_iteration_count(); -} - -void PhysicsServer3DSW::soft_body_set_total_mass(RID p_body, real_t p_total_mass) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_total_mass(p_total_mass); -} - -real_t PhysicsServer3DSW::soft_body_get_total_mass(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, 0.f); - - return soft_body->get_total_mass(); -} - -void PhysicsServer3DSW::soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_linear_stiffness(p_stiffness); -} - -real_t PhysicsServer3DSW::soft_body_get_linear_stiffness(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, 0.f); - - return soft_body->get_linear_stiffness(); -} - -void PhysicsServer3DSW::soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_pressure_coefficient(p_pressure_coefficient); -} - -real_t PhysicsServer3DSW::soft_body_get_pressure_coefficient(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, 0.f); - - return soft_body->get_pressure_coefficient(); -} - -void PhysicsServer3DSW::soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_damping_coefficient(p_damping_coefficient); -} - -real_t PhysicsServer3DSW::soft_body_get_damping_coefficient(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, 0.f); - - return soft_body->get_damping_coefficient(); -} - -void PhysicsServer3DSW::soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_drag_coefficient(p_drag_coefficient); -} - -real_t PhysicsServer3DSW::soft_body_get_drag_coefficient(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, 0.f); - - return soft_body->get_drag_coefficient(); -} - -void PhysicsServer3DSW::soft_body_set_mesh(RID p_body, const REF &p_mesh) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_mesh(p_mesh); -} - -AABB PhysicsServer3DSW::soft_body_get_bounds(RID p_body) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, AABB()); - - return soft_body->get_bounds(); -} - -void PhysicsServer3DSW::soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->set_vertex_position(p_point_index, p_global_position); -} - -Vector3 PhysicsServer3DSW::soft_body_get_point_global_position(RID p_body, int p_point_index) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, Vector3()); - - return soft_body->get_vertex_position(p_point_index); -} - -void PhysicsServer3DSW::soft_body_remove_all_pinned_points(RID p_body) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - soft_body->unpin_all_vertices(); -} - -void PhysicsServer3DSW::soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND(!soft_body); - - if (p_pin) { - soft_body->pin_vertex(p_point_index); - } else { - soft_body->unpin_vertex(p_point_index); - } -} - -bool PhysicsServer3DSW::soft_body_is_point_pinned(RID p_body, int p_point_index) const { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_body); - ERR_FAIL_COND_V(!soft_body, false); - - return soft_body->is_vertex_pinned(p_point_index); -} - -/* JOINT API */ - -RID PhysicsServer3DSW::joint_create() { - Joint3DSW *joint = memnew(Joint3DSW); - RID rid = joint_owner.make_rid(joint); - joint->set_self(rid); - return rid; -} - -void PhysicsServer3DSW::joint_clear(RID p_joint) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - if (joint->get_type() != JOINT_TYPE_MAX) { - Joint3DSW *empty_joint = memnew(Joint3DSW); - empty_joint->copy_settings_from(joint); - - joint_owner.replace(p_joint, empty_joint); - memdelete(joint); - } -} - -void PhysicsServer3DSW::joint_make_pin(RID p_joint, RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B) { - Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND(!body_A); - - if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); - p_body_B = body_A->get_space()->get_static_global_body(); - } - - Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND(!body_B); - - ERR_FAIL_COND(body_A == body_B); - - Joint3DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint3DSW *joint = memnew(PinJoint3DSW(body_A, p_local_A, body_B, p_local_B)); - - joint->copy_settings_from(prev_joint); - joint_owner.replace(p_joint, joint); - memdelete(prev_joint); -} - -void PhysicsServer3DSW::pin_joint_set_param(RID p_joint, PinJointParam p_param, real_t p_value) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); - PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); - pin_joint->set_param(p_param, p_value); -} - -real_t PhysicsServer3DSW::pin_joint_get_param(RID p_joint, PinJointParam p_param) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, 0); - PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); - return pin_joint->get_param(p_param); -} - -void PhysicsServer3DSW::pin_joint_set_local_a(RID p_joint, const Vector3 &p_A) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); - PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); - pin_joint->set_pos_a(p_A); -} - -Vector3 PhysicsServer3DSW::pin_joint_get_local_a(RID p_joint) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, Vector3()); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, Vector3()); - PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); - return pin_joint->get_position_a(); -} - -void PhysicsServer3DSW::pin_joint_set_local_b(RID p_joint, const Vector3 &p_B) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_PIN); - PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); - pin_joint->set_pos_b(p_B); -} - -Vector3 PhysicsServer3DSW::pin_joint_get_local_b(RID p_joint) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, Vector3()); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_PIN, Vector3()); - PinJoint3DSW *pin_joint = static_cast<PinJoint3DSW *>(joint); - return pin_joint->get_position_b(); -} - -void PhysicsServer3DSW::joint_make_hinge(RID p_joint, RID p_body_A, const Transform3D &p_frame_A, RID p_body_B, const Transform3D &p_frame_B) { - Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND(!body_A); - - if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); - p_body_B = body_A->get_space()->get_static_global_body(); - } - - Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND(!body_B); - - ERR_FAIL_COND(body_A == body_B); - - Joint3DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint3DSW *joint = memnew(HingeJoint3DSW(body_A, body_B, p_frame_A, p_frame_B)); - - joint->copy_settings_from(prev_joint); - joint_owner.replace(p_joint, joint); - memdelete(prev_joint); -} - -void PhysicsServer3DSW::joint_make_hinge_simple(RID p_joint, RID p_body_A, const Vector3 &p_pivot_A, const Vector3 &p_axis_A, RID p_body_B, const Vector3 &p_pivot_B, const Vector3 &p_axis_B) { - Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND(!body_A); - - if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); - p_body_B = body_A->get_space()->get_static_global_body(); - } - - Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND(!body_B); - - ERR_FAIL_COND(body_A == body_B); - - Joint3DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint3DSW *joint = memnew(HingeJoint3DSW(body_A, body_B, p_pivot_A, p_pivot_B, p_axis_A, p_axis_B)); - - joint->copy_settings_from(prev_joint); - joint_owner.replace(p_joint, joint); - memdelete(prev_joint); -} - -void PhysicsServer3DSW::hinge_joint_set_param(RID p_joint, HingeJointParam p_param, real_t p_value) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_HINGE); - HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint); - hinge_joint->set_param(p_param, p_value); -} - -real_t PhysicsServer3DSW::hinge_joint_get_param(RID p_joint, HingeJointParam p_param) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_HINGE, 0); - HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint); - return hinge_joint->get_param(p_param); -} - -void PhysicsServer3DSW::hinge_joint_set_flag(RID p_joint, HingeJointFlag p_flag, bool p_value) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_HINGE); - HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint); - hinge_joint->set_flag(p_flag, p_value); -} - -bool PhysicsServer3DSW::hinge_joint_get_flag(RID p_joint, HingeJointFlag p_flag) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, false); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_HINGE, false); - HingeJoint3DSW *hinge_joint = static_cast<HingeJoint3DSW *>(joint); - return hinge_joint->get_flag(p_flag); -} - -void PhysicsServer3DSW::joint_set_solver_priority(RID p_joint, int p_priority) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - joint->set_priority(p_priority); -} - -int PhysicsServer3DSW::joint_get_solver_priority(RID p_joint) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, 0); - return joint->get_priority(); -} - -void PhysicsServer3DSW::joint_disable_collisions_between_bodies(RID p_joint, const bool p_disable) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - - joint->disable_collisions_between_bodies(p_disable); - - if (2 == joint->get_body_count()) { - Body3DSW *body_a = *joint->get_body_ptr(); - Body3DSW *body_b = *(joint->get_body_ptr() + 1); - - if (p_disable) { - body_add_collision_exception(body_a->get_self(), body_b->get_self()); - body_add_collision_exception(body_b->get_self(), body_a->get_self()); - } else { - body_remove_collision_exception(body_a->get_self(), body_b->get_self()); - body_remove_collision_exception(body_b->get_self(), body_a->get_self()); - } - } -} - -bool PhysicsServer3DSW::joint_is_disabled_collisions_between_bodies(RID p_joint) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, true); - - return joint->is_disabled_collisions_between_bodies(); -} - -PhysicsServer3DSW::JointType PhysicsServer3DSW::joint_get_type(RID p_joint) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, JOINT_TYPE_PIN); - return joint->get_type(); -} - -void PhysicsServer3DSW::joint_make_slider(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { - Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND(!body_A); - - if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); - p_body_B = body_A->get_space()->get_static_global_body(); - } - - Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND(!body_B); - - ERR_FAIL_COND(body_A == body_B); - - Joint3DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint3DSW *joint = memnew(SliderJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B)); - - joint->copy_settings_from(prev_joint); - joint_owner.replace(p_joint, joint); - memdelete(prev_joint); -} - -void PhysicsServer3DSW::slider_joint_set_param(RID p_joint, SliderJointParam p_param, real_t p_value) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_SLIDER); - SliderJoint3DSW *slider_joint = static_cast<SliderJoint3DSW *>(joint); - slider_joint->set_param(p_param, p_value); -} - -real_t PhysicsServer3DSW::slider_joint_get_param(RID p_joint, SliderJointParam p_param) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_CONE_TWIST, 0); - SliderJoint3DSW *slider_joint = static_cast<SliderJoint3DSW *>(joint); - return slider_joint->get_param(p_param); -} - -void PhysicsServer3DSW::joint_make_cone_twist(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { - Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND(!body_A); - - if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); - p_body_B = body_A->get_space()->get_static_global_body(); - } - - Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND(!body_B); - - ERR_FAIL_COND(body_A == body_B); - - Joint3DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint3DSW *joint = memnew(ConeTwistJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B)); - - joint->copy_settings_from(prev_joint); - joint_owner.replace(p_joint, joint); - memdelete(prev_joint); -} - -void PhysicsServer3DSW::cone_twist_joint_set_param(RID p_joint, ConeTwistJointParam p_param, real_t p_value) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_CONE_TWIST); - ConeTwistJoint3DSW *cone_twist_joint = static_cast<ConeTwistJoint3DSW *>(joint); - cone_twist_joint->set_param(p_param, p_value); -} - -real_t PhysicsServer3DSW::cone_twist_joint_get_param(RID p_joint, ConeTwistJointParam p_param) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_CONE_TWIST, 0); - ConeTwistJoint3DSW *cone_twist_joint = static_cast<ConeTwistJoint3DSW *>(joint); - return cone_twist_joint->get_param(p_param); -} - -void PhysicsServer3DSW::joint_make_generic_6dof(RID p_joint, RID p_body_A, const Transform3D &p_local_frame_A, RID p_body_B, const Transform3D &p_local_frame_B) { - Body3DSW *body_A = body_owner.getornull(p_body_A); - ERR_FAIL_COND(!body_A); - - if (!p_body_B.is_valid()) { - ERR_FAIL_COND(!body_A->get_space()); - p_body_B = body_A->get_space()->get_static_global_body(); - } - - Body3DSW *body_B = body_owner.getornull(p_body_B); - ERR_FAIL_COND(!body_B); - - ERR_FAIL_COND(body_A == body_B); - - Joint3DSW *prev_joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(prev_joint == nullptr); - - Joint3DSW *joint = memnew(Generic6DOFJoint3DSW(body_A, body_B, p_local_frame_A, p_local_frame_B, true)); - - joint->copy_settings_from(prev_joint); - joint_owner.replace(p_joint, joint); - memdelete(prev_joint); -} - -void PhysicsServer3DSW::generic_6dof_joint_set_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param, real_t p_value) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF); - Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint); - generic_6dof_joint->set_param(p_axis, p_param, p_value); -} - -real_t PhysicsServer3DSW::generic_6dof_joint_get_param(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisParam p_param) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, 0); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, 0); - Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint); - return generic_6dof_joint->get_param(p_axis, p_param); -} - -void PhysicsServer3DSW::generic_6dof_joint_set_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag, bool p_enable) { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND(!joint); - ERR_FAIL_COND(joint->get_type() != JOINT_TYPE_6DOF); - Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint); - generic_6dof_joint->set_flag(p_axis, p_flag, p_enable); -} - -bool PhysicsServer3DSW::generic_6dof_joint_get_flag(RID p_joint, Vector3::Axis p_axis, G6DOFJointAxisFlag p_flag) const { - Joint3DSW *joint = joint_owner.getornull(p_joint); - ERR_FAIL_COND_V(!joint, false); - ERR_FAIL_COND_V(joint->get_type() != JOINT_TYPE_6DOF, false); - Generic6DOFJoint3DSW *generic_6dof_joint = static_cast<Generic6DOFJoint3DSW *>(joint); - return generic_6dof_joint->get_flag(p_axis, p_flag); -} - -void PhysicsServer3DSW::free(RID p_rid) { - _update_shapes(); //just in case - - if (shape_owner.owns(p_rid)) { - Shape3DSW *shape = shape_owner.getornull(p_rid); - - while (shape->get_owners().size()) { - ShapeOwner3DSW *so = shape->get_owners().front()->key(); - so->remove_shape(shape); - } - - shape_owner.free(p_rid); - memdelete(shape); - } else if (body_owner.owns(p_rid)) { - Body3DSW *body = body_owner.getornull(p_rid); - - /* - if (body->get_state_query()) - _clear_query(body->get_state_query()); - - if (body->get_direct_state_query()) - _clear_query(body->get_direct_state_query()); - */ - - body->set_space(nullptr); - - while (body->get_shape_count()) { - body->remove_shape(0); - } - - body_owner.free(p_rid); - memdelete(body); - } else if (soft_body_owner.owns(p_rid)) { - SoftBody3DSW *soft_body = soft_body_owner.getornull(p_rid); - - soft_body->set_space(nullptr); - - soft_body_owner.free(p_rid); - memdelete(soft_body); - } else if (area_owner.owns(p_rid)) { - Area3DSW *area = area_owner.getornull(p_rid); - - /* - if (area->get_monitor_query()) - _clear_query(area->get_monitor_query()); - */ - - area->set_space(nullptr); - - while (area->get_shape_count()) { - area->remove_shape(0); - } - - area_owner.free(p_rid); - memdelete(area); - } else if (space_owner.owns(p_rid)) { - Space3DSW *space = space_owner.getornull(p_rid); - - while (space->get_objects().size()) { - CollisionObject3DSW *co = (CollisionObject3DSW *)space->get_objects().front()->get(); - co->set_space(nullptr); - } - - active_spaces.erase(space); - free(space->get_default_area()->get_self()); - free(space->get_static_global_body()); - - space_owner.free(p_rid); - memdelete(space); - } else if (joint_owner.owns(p_rid)) { - Joint3DSW *joint = joint_owner.getornull(p_rid); - - joint_owner.free(p_rid); - memdelete(joint); - - } else { - ERR_FAIL_MSG("Invalid ID."); - } -}; - -void PhysicsServer3DSW::set_active(bool p_active) { - active = p_active; -}; - -void PhysicsServer3DSW::set_collision_iterations(int p_iterations) { - iterations = p_iterations; -}; - -void PhysicsServer3DSW::init() { - iterations = 8; // 8? - stepper = memnew(Step3DSW); -}; - -void PhysicsServer3DSW::step(real_t p_step) { -#ifndef _3D_DISABLED - - if (!active) { - return; - } - - _update_shapes(); - - island_count = 0; - active_objects = 0; - collision_pairs = 0; - for (Set<const Space3DSW *>::Element *E = active_spaces.front(); E; E = E->next()) { - stepper->step((Space3DSW *)E->get(), p_step, iterations); - island_count += E->get()->get_island_count(); - active_objects += E->get()->get_active_objects(); - collision_pairs += E->get()->get_collision_pairs(); - } -#endif -} - -void PhysicsServer3DSW::sync() { - doing_sync = true; -}; - -void PhysicsServer3DSW::flush_queries() { -#ifndef _3D_DISABLED - - if (!active) { - return; - } - - flushing_queries = true; - - uint64_t time_beg = OS::get_singleton()->get_ticks_usec(); - - for (Set<const Space3DSW *>::Element *E = active_spaces.front(); E; E = E->next()) { - Space3DSW *space = (Space3DSW *)E->get(); - space->call_queries(); - } - - flushing_queries = false; - - if (EngineDebugger::is_profiling("servers")) { - uint64_t total_time[Space3DSW::ELAPSED_TIME_MAX]; - static const char *time_name[Space3DSW::ELAPSED_TIME_MAX] = { - "integrate_forces", - "generate_islands", - "setup_constraints", - "solve_constraints", - "integrate_velocities" - }; - - for (int i = 0; i < Space3DSW::ELAPSED_TIME_MAX; i++) { - total_time[i] = 0; - } - - for (Set<const Space3DSW *>::Element *E = active_spaces.front(); E; E = E->next()) { - for (int i = 0; i < Space3DSW::ELAPSED_TIME_MAX; i++) { - total_time[i] += E->get()->get_elapsed_time(Space3DSW::ElapsedTime(i)); - } - } - - Array values; - values.resize(Space3DSW::ELAPSED_TIME_MAX * 2); - for (int i = 0; i < Space3DSW::ELAPSED_TIME_MAX; i++) { - values[i * 2 + 0] = time_name[i]; - values[i * 2 + 1] = USEC_TO_SEC(total_time[i]); - } - values.push_back("flush_queries"); - values.push_back(USEC_TO_SEC(OS::get_singleton()->get_ticks_usec() - time_beg)); - - values.push_front("physics"); - EngineDebugger::profiler_add_frame_data("servers", values); - } -#endif -}; - -void PhysicsServer3DSW::end_sync() { - doing_sync = false; -}; - -void PhysicsServer3DSW::finish() { - memdelete(stepper); -}; - -int PhysicsServer3DSW::get_process_info(ProcessInfo p_info) { - switch (p_info) { - case INFO_ACTIVE_OBJECTS: { - return active_objects; - } break; - case INFO_COLLISION_PAIRS: { - return collision_pairs; - } break; - case INFO_ISLAND_COUNT: { - return island_count; - } break; - } - - return 0; -} - -void PhysicsServer3DSW::_update_shapes() { - while (pending_shape_update_list.first()) { - pending_shape_update_list.first()->self()->_shape_changed(); - pending_shape_update_list.remove(pending_shape_update_list.first()); - } -} - -void PhysicsServer3DSW::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) { - CollCbkData *cbk = (CollCbkData *)p_userdata; - - if (cbk->max == 0) { - return; - } - - if (cbk->amount == cbk->max) { - //find least deep - real_t min_depth = 1e20; - int min_depth_idx = 0; - for (int i = 0; i < cbk->amount; i++) { - real_t d = cbk->ptr[i * 2 + 0].distance_squared_to(cbk->ptr[i * 2 + 1]); - if (d < min_depth) { - min_depth = d; - min_depth_idx = i; - } - } - - real_t d = p_point_A.distance_squared_to(p_point_B); - if (d < min_depth) { - return; - } - cbk->ptr[min_depth_idx * 2 + 0] = p_point_A; - cbk->ptr[min_depth_idx * 2 + 1] = p_point_B; - - } else { - cbk->ptr[cbk->amount * 2 + 0] = p_point_A; - cbk->ptr[cbk->amount * 2 + 1] = p_point_B; - cbk->amount++; - } -} - -PhysicsServer3DSW *PhysicsServer3DSW::singletonsw = nullptr; -PhysicsServer3DSW::PhysicsServer3DSW(bool p_using_threads) { - singletonsw = this; - BroadPhase3DSW::create_func = BroadPhase3DBVH::_create; - - island_count = 0; - active_objects = 0; - collision_pairs = 0; - using_threads = p_using_threads; - active = true; - flushing_queries = false; - doing_sync = false; -}; diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp index 4660b83f4d..76f0b74c72 100644 --- a/servers/physics_server_2d.cpp +++ b/servers/physics_server_2d.cpp @@ -77,6 +77,8 @@ void PhysicsDirectBodyState2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_total_linear_damp"), &PhysicsDirectBodyState2D::get_total_linear_damp); ClassDB::bind_method(D_METHOD("get_total_angular_damp"), &PhysicsDirectBodyState2D::get_total_angular_damp); + ClassDB::bind_method(D_METHOD("get_center_of_mass"), &PhysicsDirectBodyState2D::get_center_of_mass); + ClassDB::bind_method(D_METHOD("get_center_of_mass_local"), &PhysicsDirectBodyState2D::get_center_of_mass_local); ClassDB::bind_method(D_METHOD("get_inverse_mass"), &PhysicsDirectBodyState2D::get_inverse_mass); ClassDB::bind_method(D_METHOD("get_inverse_inertia"), &PhysicsDirectBodyState2D::get_inverse_inertia); @@ -111,7 +113,6 @@ void PhysicsDirectBodyState2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_contact_collider_id", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_id); ClassDB::bind_method(D_METHOD("get_contact_collider_object", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_object); ClassDB::bind_method(D_METHOD("get_contact_collider_shape", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_shape); - ClassDB::bind_method(D_METHOD("get_contact_collider_shape_metadata", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_shape_metadata); ClassDB::bind_method(D_METHOD("get_contact_collider_velocity_at_position", "contact_idx"), &PhysicsDirectBodyState2D::get_contact_collider_velocity_at_position); ClassDB::bind_method(D_METHOD("get_step"), &PhysicsDirectBodyState2D::get_step); ClassDB::bind_method(D_METHOD("integrate_forces"), &PhysicsDirectBodyState2D::integrate_forces); @@ -123,6 +124,8 @@ void PhysicsDirectBodyState2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_angular_damp"), "", "get_total_angular_damp"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "total_linear_damp"), "", "get_total_linear_damp"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "total_gravity"), "", "get_total_gravity"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass"), "", "get_center_of_mass"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "center_of_mass_local"), "", "get_center_of_mass_local"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "sleeping"), "set_sleep_state", "is_sleeping"); @@ -133,95 +136,136 @@ PhysicsDirectBodyState2D::PhysicsDirectBodyState2D() {} /////////////////////////////////////////////////////// -void PhysicsShapeQueryParameters2D::set_shape(const RES &p_shape_ref) { - ERR_FAIL_COND(p_shape_ref.is_null()); - shape_ref = p_shape_ref; - shape = p_shape_ref->get_rid(); -} - -RES PhysicsShapeQueryParameters2D::get_shape() const { - return shape_ref; +void PhysicsRayQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) { + parameters.exclude.clear(); + for (int i = 0; i < p_exclude.size(); i++) { + parameters.exclude.insert(p_exclude[i]); + } } -void PhysicsShapeQueryParameters2D::set_shape_rid(const RID &p_shape) { - if (shape != p_shape) { - shape_ref = RES(); - shape = p_shape; +Vector<RID> PhysicsRayQueryParameters2D::get_exclude() const { + Vector<RID> ret; + ret.resize(parameters.exclude.size()); + int idx = 0; + for (Set<RID>::Element *E = parameters.exclude.front(); E; E = E->next()) { + ret.write[idx++] = E->get(); } + return ret; } -RID PhysicsShapeQueryParameters2D::get_shape_rid() const { - return shape; -} +void PhysicsRayQueryParameters2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_from", "from"), &PhysicsRayQueryParameters2D::set_from); + ClassDB::bind_method(D_METHOD("get_from"), &PhysicsRayQueryParameters2D::get_from); -void PhysicsShapeQueryParameters2D::set_transform(const Transform2D &p_transform) { - transform = p_transform; -} + ClassDB::bind_method(D_METHOD("set_to", "to"), &PhysicsRayQueryParameters2D::set_to); + ClassDB::bind_method(D_METHOD("get_to"), &PhysicsRayQueryParameters2D::get_to); -Transform2D PhysicsShapeQueryParameters2D::get_transform() const { - return transform; -} + ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &PhysicsRayQueryParameters2D::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsRayQueryParameters2D::get_collision_mask); -void PhysicsShapeQueryParameters2D::set_motion(const Vector2 &p_motion) { - motion = p_motion; -} + ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &PhysicsRayQueryParameters2D::set_exclude); + ClassDB::bind_method(D_METHOD("get_exclude"), &PhysicsRayQueryParameters2D::get_exclude); -Vector2 PhysicsShapeQueryParameters2D::get_motion() const { - return motion; -} + ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &PhysicsRayQueryParameters2D::set_collide_with_bodies); + ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &PhysicsRayQueryParameters2D::is_collide_with_bodies_enabled); -void PhysicsShapeQueryParameters2D::set_margin(real_t p_margin) { - margin = p_margin; -} + ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsRayQueryParameters2D::set_collide_with_areas); + ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsRayQueryParameters2D::is_collide_with_areas_enabled); -real_t PhysicsShapeQueryParameters2D::get_margin() const { - return margin; -} + ClassDB::bind_method(D_METHOD("set_hit_from_inside", "enable"), &PhysicsRayQueryParameters2D::set_hit_from_inside); + ClassDB::bind_method(D_METHOD("is_hit_from_inside_enabled"), &PhysicsRayQueryParameters2D::is_hit_from_inside_enabled); -void PhysicsShapeQueryParameters2D::set_collision_mask(uint32_t p_collision_mask) { - collision_mask = p_collision_mask; + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "from"), "set_from", "get_from"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "to"), "set_to", "get_to"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled"); } -uint32_t PhysicsShapeQueryParameters2D::get_collision_mask() const { - return collision_mask; -} +/////////////////////////////////////////////////////// -void PhysicsShapeQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) { - exclude.clear(); +void PhysicsPointQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) { + parameters.exclude.clear(); for (int i = 0; i < p_exclude.size(); i++) { - exclude.insert(p_exclude[i]); + parameters.exclude.insert(p_exclude[i]); } } -Vector<RID> PhysicsShapeQueryParameters2D::get_exclude() const { +Vector<RID> PhysicsPointQueryParameters2D::get_exclude() const { Vector<RID> ret; - ret.resize(exclude.size()); + ret.resize(parameters.exclude.size()); int idx = 0; - for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) { - ret.write[idx] = E->get(); + for (Set<RID>::Element *E = parameters.exclude.front(); E; E = E->next()) { + ret.write[idx++] = E->get(); } return ret; } -void PhysicsShapeQueryParameters2D::set_collide_with_bodies(bool p_enable) { - collide_with_bodies = p_enable; +void PhysicsPointQueryParameters2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_position", "position"), &PhysicsPointQueryParameters2D::set_position); + ClassDB::bind_method(D_METHOD("get_position"), &PhysicsPointQueryParameters2D::get_position); + + ClassDB::bind_method(D_METHOD("set_canvas_instance_id", "canvas_instance_id"), &PhysicsPointQueryParameters2D::set_canvas_instance_id); + ClassDB::bind_method(D_METHOD("get_canvas_instance_id"), &PhysicsPointQueryParameters2D::get_canvas_instance_id); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &PhysicsPointQueryParameters2D::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsPointQueryParameters2D::get_collision_mask); + + ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &PhysicsPointQueryParameters2D::set_exclude); + ClassDB::bind_method(D_METHOD("get_exclude"), &PhysicsPointQueryParameters2D::get_exclude); + + ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &PhysicsPointQueryParameters2D::set_collide_with_bodies); + ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &PhysicsPointQueryParameters2D::is_collide_with_bodies_enabled); + + ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsPointQueryParameters2D::set_collide_with_areas); + ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsPointQueryParameters2D::is_collide_with_areas_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "position"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "canvas_instance_id", PROPERTY_HINT_OBJECT_ID), "set_canvas_instance_id", "get_canvas_instance_id"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); } -bool PhysicsShapeQueryParameters2D::is_collide_with_bodies_enabled() const { - return collide_with_bodies; +/////////////////////////////////////////////////////// + +void PhysicsShapeQueryParameters2D::set_shape(const RES &p_shape_ref) { + ERR_FAIL_COND(p_shape_ref.is_null()); + shape_ref = p_shape_ref; + parameters.shape_rid = p_shape_ref->get_rid(); } -void PhysicsShapeQueryParameters2D::set_collide_with_areas(bool p_enable) { - collide_with_areas = p_enable; +void PhysicsShapeQueryParameters2D::set_shape_rid(const RID &p_shape) { + if (parameters.shape_rid != p_shape) { + shape_ref = RES(); + parameters.shape_rid = p_shape; + } +} + +void PhysicsShapeQueryParameters2D::set_exclude(const Vector<RID> &p_exclude) { + parameters.exclude.clear(); + for (int i = 0; i < p_exclude.size(); i++) { + parameters.exclude.insert(p_exclude[i]); + } } -bool PhysicsShapeQueryParameters2D::is_collide_with_areas_enabled() const { - return collide_with_areas; +Vector<RID> PhysicsShapeQueryParameters2D::get_exclude() const { + Vector<RID> ret; + ret.resize(parameters.exclude.size()); + int idx = 0; + for (Set<RID>::Element *E = parameters.exclude.front(); E; E = E->next()) { + ret.write[idx++] = E->get(); + } + return ret; } void PhysicsShapeQueryParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shape", "shape"), &PhysicsShapeQueryParameters2D::set_shape); ClassDB::bind_method(D_METHOD("get_shape"), &PhysicsShapeQueryParameters2D::get_shape); + ClassDB::bind_method(D_METHOD("set_shape_rid", "shape"), &PhysicsShapeQueryParameters2D::set_shape_rid); ClassDB::bind_method(D_METHOD("get_shape_rid"), &PhysicsShapeQueryParameters2D::get_shape_rid); @@ -247,7 +291,7 @@ void PhysicsShapeQueryParameters2D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsShapeQueryParameters2D::is_collide_with_areas_enabled); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_2D_PHYSICS), "set_collision_mask", "get_collision_mask"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::RID) + ":"), "set_exclude", "get_exclude"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape2D"), "set_shape", "get_shape"); @@ -257,44 +301,58 @@ void PhysicsShapeQueryParameters2D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); } -PhysicsShapeQueryParameters2D::PhysicsShapeQueryParameters2D() { - margin = 0; - collision_mask = 0x7FFFFFFF; - collide_with_bodies = true; - collide_with_areas = false; -} +/////////////////////////////////////////////////////// -Dictionary PhysicsDirectSpaceState2D::_intersect_ray(const Vector2 &p_from, const Vector2 &p_to, const Vector<RID> &p_exclude, uint32_t p_layers, bool p_collide_with_bodies, bool p_collide_with_areas) { - RayResult inters; - Set<RID> exclude; - for (int i = 0; i < p_exclude.size(); i++) { - exclude.insert(p_exclude[i]); - } +Dictionary PhysicsDirectSpaceState2D::_intersect_ray(const Ref<PhysicsRayQueryParameters2D> &p_ray_query) { + ERR_FAIL_COND_V(!p_ray_query.is_valid(), Dictionary()); - bool res = intersect_ray(p_from, p_to, inters, exclude, p_layers, p_collide_with_bodies, p_collide_with_areas); + RayResult result; + bool res = intersect_ray(p_ray_query->get_parameters(), result); if (!res) { return Dictionary(); } Dictionary d; - d["position"] = inters.position; - d["normal"] = inters.normal; - d["collider_id"] = inters.collider_id; - d["collider"] = inters.collider; - d["shape"] = inters.shape; - d["rid"] = inters.rid; - d["metadata"] = inters.metadata; + d["position"] = result.position; + d["normal"] = result.normal; + d["collider_id"] = result.collider_id; + d["collider"] = result.collider; + d["shape"] = result.shape; + d["rid"] = result.rid; return d; } +Array PhysicsDirectSpaceState2D::_intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results) { + Vector<ShapeResult> ret; + ret.resize(p_max_results); + + int rc = intersect_point(p_point_query->get_parameters(), ret.ptrw(), ret.size()); + + if (rc == 0) { + return Array(); + } + + Array r; + r.resize(rc); + for (int i = 0; i < rc; i++) { + Dictionary d; + d["rid"] = ret[i].rid; + d["collider_id"] = ret[i].collider_id; + d["collider"] = ret[i].collider; + d["shape"] = ret[i].shape; + r[i] = d; + } + return r; +} + Array PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); Vector<ShapeResult> sr; sr.resize(p_max_results); - int rc = intersect_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, sr.ptrw(), sr.size(), p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); + int rc = intersect_shape(p_shape_query->get_parameters(), sr.ptrw(), sr.size()); Array ret; ret.resize(rc); for (int i = 0; i < rc; i++) { @@ -303,7 +361,6 @@ Array PhysicsDirectSpaceState2D::_intersect_shape(const Ref<PhysicsShapeQueryPar d["collider_id"] = sr[i].collider_id; d["collider"] = sr[i].collider; d["shape"] = sr[i].shape; - d["metadata"] = sr[i].metadata; ret[i] = d; } @@ -314,7 +371,7 @@ Array PhysicsDirectSpaceState2D::_cast_motion(const Ref<PhysicsShapeQueryParamet ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); real_t closest_safe, closest_unsafe; - bool res = cast_motion(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, closest_safe, closest_unsafe, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); + bool res = cast_motion(p_shape_query->get_parameters(), closest_safe, closest_unsafe); if (!res) { return Array(); } @@ -325,55 +382,13 @@ Array PhysicsDirectSpaceState2D::_cast_motion(const Ref<PhysicsShapeQueryParamet return ret; } -Array PhysicsDirectSpaceState2D::_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++) { - exclude.insert(p_exclude[i]); - } - - Vector<ShapeResult> ret; - ret.resize(p_max_results); - - 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(); - } - - Array r; - r.resize(rc); - for (int i = 0; i < rc; i++) { - Dictionary d; - d["rid"] = ret[i].rid; - d["collider_id"] = ret[i].collider_id; - d["collider"] = ret[i].collider; - d["shape"] = ret[i].shape; - d["metadata"] = ret[i].metadata; - r[i] = d; - } - return r; -} - -Array PhysicsDirectSpaceState2D::_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 PhysicsDirectSpaceState2D::_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 PhysicsDirectSpaceState2D::_collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); Vector<Vector2> ret; ret.resize(p_max_results * 2); int rc = 0; - bool res = collide_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, ret.ptrw(), p_max_results, rc, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); + bool res = collide_shape(p_shape_query->get_parameters(), ret.ptrw(), p_max_results, rc); if (!res) { return Array(); } @@ -390,7 +405,7 @@ Dictionary PhysicsDirectSpaceState2D::_get_rest_info(const Ref<PhysicsShapeQuery ShapeRestInfo sri; - bool res = rest_info(p_shape_query->shape, p_shape_query->transform, p_shape_query->motion, p_shape_query->margin, &sri, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); + bool res = rest_info(p_shape_query->get_parameters(), &sri); Dictionary r; if (!res) { return r; @@ -402,7 +417,6 @@ Dictionary PhysicsDirectSpaceState2D::_get_rest_info(const Ref<PhysicsShapeQuery r["collider_id"] = sri.collider_id; r["shape"] = sri.shape; r["linear_velocity"] = sri.linear_velocity; - r["metadata"] = sri.metadata; return r; } @@ -411,13 +425,79 @@ PhysicsDirectSpaceState2D::PhysicsDirectSpaceState2D() { } void PhysicsDirectSpaceState2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("intersect_point", "point", "max_results", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_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_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_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_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState2D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_intersect_shape, DEFVAL(32)); - ClassDB::bind_method(D_METHOD("cast_motion", "shape"), &PhysicsDirectSpaceState2D::_cast_motion); - ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState2D::_collide_shape, DEFVAL(32)); - ClassDB::bind_method(D_METHOD("get_rest_info", "shape"), &PhysicsDirectSpaceState2D::_get_rest_info); + ClassDB::bind_method(D_METHOD("intersect_point", "parameters", "max_results"), &PhysicsDirectSpaceState2D::_intersect_point, DEFVAL(32)); + ClassDB::bind_method(D_METHOD("intersect_ray", "parameters"), &PhysicsDirectSpaceState2D::_intersect_ray); + ClassDB::bind_method(D_METHOD("intersect_shape", "parameters", "max_results"), &PhysicsDirectSpaceState2D::_intersect_shape, DEFVAL(32)); + ClassDB::bind_method(D_METHOD("cast_motion", "parameters"), &PhysicsDirectSpaceState2D::_cast_motion); + ClassDB::bind_method(D_METHOD("collide_shape", "parameters", "max_results"), &PhysicsDirectSpaceState2D::_collide_shape, DEFVAL(32)); + ClassDB::bind_method(D_METHOD("get_rest_info", "parameters"), &PhysicsDirectSpaceState2D::_get_rest_info); +} + +/////////////////////////////// + +Vector<RID> PhysicsTestMotionParameters2D::get_exclude_bodies() const { + Vector<RID> exclude; + exclude.resize(parameters.exclude_bodies.size()); + + int body_index = 0; + for (RID body : parameters.exclude_bodies) { + exclude.write[body_index++] = body; + } + + return exclude; +} + +void PhysicsTestMotionParameters2D::set_exclude_bodies(const Vector<RID> &p_exclude) { + for (RID body : p_exclude) { + parameters.exclude_bodies.insert(body); + } +} + +Array PhysicsTestMotionParameters2D::get_exclude_objects() const { + Array exclude; + exclude.resize(parameters.exclude_objects.size()); + + int object_index = 0; + for (ObjectID object_id : parameters.exclude_objects) { + exclude[object_index++] = object_id; + } + + return exclude; +} + +void PhysicsTestMotionParameters2D::set_exclude_objects(const Array &p_exclude) { + for (int i = 0; i < p_exclude.size(); ++i) { + ObjectID object_id = p_exclude[i]; + ERR_CONTINUE(object_id.is_null()); + parameters.exclude_objects.insert(object_id); + } +} + +void PhysicsTestMotionParameters2D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_from"), &PhysicsTestMotionParameters2D::get_from); + ClassDB::bind_method(D_METHOD("set_from", "from"), &PhysicsTestMotionParameters2D::set_from); + + ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionParameters2D::get_motion); + ClassDB::bind_method(D_METHOD("set_motion", "motion"), &PhysicsTestMotionParameters2D::set_motion); + + ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsTestMotionParameters2D::get_margin); + ClassDB::bind_method(D_METHOD("set_margin", "margin"), &PhysicsTestMotionParameters2D::set_margin); + + ClassDB::bind_method(D_METHOD("is_collide_separation_ray_enabled"), &PhysicsTestMotionParameters2D::is_collide_separation_ray_enabled); + ClassDB::bind_method(D_METHOD("set_collide_separation_ray_enabled", "enabled"), &PhysicsTestMotionParameters2D::set_collide_separation_ray_enabled); + + ClassDB::bind_method(D_METHOD("get_exclude_bodies"), &PhysicsTestMotionParameters2D::get_exclude_bodies); + ClassDB::bind_method(D_METHOD("set_exclude_bodies", "exclude_list"), &PhysicsTestMotionParameters2D::set_exclude_bodies); + + ClassDB::bind_method(D_METHOD("get_exclude_objects"), &PhysicsTestMotionParameters2D::get_exclude_objects); + ClassDB::bind_method(D_METHOD("set_exclude_objects", "exclude_list"), &PhysicsTestMotionParameters2D::set_exclude_objects); + + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM2D, "from"), "set_from", "get_from"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_separation_ray"), "set_collide_separation_ray_enabled", "is_collide_separation_ray_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_bodies", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude_bodies", "get_exclude_bodies"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_objects"), "set_exclude_objects", "get_exclude_objects"); } /////////////////////////////// @@ -458,6 +538,10 @@ int PhysicsTestMotionResult2D::get_collider_shape() const { return result.collider_shape; } +int PhysicsTestMotionResult2D::get_collision_local_shape() const { + return result.collision_local_shape; +} + real_t PhysicsTestMotionResult2D::get_collision_depth() const { return result.collision_depth; } @@ -480,40 +564,27 @@ void PhysicsTestMotionResult2D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_collider_rid"), &PhysicsTestMotionResult2D::get_collider_rid); ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsTestMotionResult2D::get_collider); ClassDB::bind_method(D_METHOD("get_collider_shape"), &PhysicsTestMotionResult2D::get_collider_shape); + ClassDB::bind_method(D_METHOD("get_collision_local_shape"), &PhysicsTestMotionResult2D::get_collision_local_shape); ClassDB::bind_method(D_METHOD("get_collision_depth"), &PhysicsTestMotionResult2D::get_collision_depth); ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult2D::get_collision_safe_fraction); ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult2D::get_collision_unsafe_fraction); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "travel"), "", "get_travel"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "remainder"), "", "get_remainder"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_point"), "", "get_collision_point"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collision_normal"), "", "get_collision_normal"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "collider_velocity"), "", "get_collider_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id", PROPERTY_HINT_OBJECT_ID), "", "get_collider_id"); - ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_collider_shape"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_depth"), "", "get_collision_depth"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_safe_fraction"), "", "get_collision_safe_fraction"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_unsafe_fraction"), "", "get_collision_unsafe_fraction"); } /////////////////////////////////////// -bool PhysicsServer2D::_body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin, const Ref<PhysicsTestMotionResult2D> &p_result, bool p_collide_separation_ray, const Vector<RID> &p_exclude) { - MotionResult *r = nullptr; +bool PhysicsServer2D::_body_test_motion(RID p_body, const Ref<PhysicsTestMotionParameters2D> &p_parameters, const Ref<PhysicsTestMotionResult2D> &p_result) { + ERR_FAIL_COND_V(!p_parameters.is_valid(), false); + + MotionResult *result_ptr = nullptr; if (p_result.is_valid()) { - r = p_result->get_result_ptr(); - } - Set<RID> exclude; - for (int i = 0; i < p_exclude.size(); i++) { - exclude.insert(p_exclude[i]); + result_ptr = p_result->get_result_ptr(); } - return body_test_motion(p_body, p_from, p_motion, p_margin, r, p_collide_separation_ray, exclude); + + return body_test_motion(p_body, p_parameters->get_parameters(), result_ptr); } void PhysicsServer2D::_bind_methods() { - ClassDB::bind_method(D_METHOD("world_margin_shape_create"), &PhysicsServer2D::world_margin_shape_create); + ClassDB::bind_method(D_METHOD("world_boundary_shape_create"), &PhysicsServer2D::world_boundary_shape_create); ClassDB::bind_method(D_METHOD("separation_ray_shape_create"), &PhysicsServer2D::separation_ray_shape_create); ClassDB::bind_method(D_METHOD("segment_shape_create"), &PhysicsServer2D::segment_shape_create); ClassDB::bind_method(D_METHOD("circle_shape_create"), &PhysicsServer2D::circle_shape_create); @@ -538,9 +609,6 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("area_set_space", "area", "space"), &PhysicsServer2D::area_set_space); ClassDB::bind_method(D_METHOD("area_get_space", "area"), &PhysicsServer2D::area_get_space); - ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &PhysicsServer2D::area_set_space_override_mode); - ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &PhysicsServer2D::area_get_space_override_mode); - ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer2D::area_add_shape, DEFVAL(Transform2D()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &PhysicsServer2D::area_set_shape); ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &PhysicsServer2D::area_set_shape_transform); @@ -568,8 +636,8 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("area_attach_canvas_instance_id", "area", "id"), &PhysicsServer2D::area_attach_canvas_instance_id); ClassDB::bind_method(D_METHOD("area_get_canvas_instance_id", "area"), &PhysicsServer2D::area_get_canvas_instance_id); - ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &PhysicsServer2D::area_set_monitor_callback); - ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &PhysicsServer2D::area_set_area_monitor_callback); + ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "callback"), &PhysicsServer2D::area_set_monitor_callback); + ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "callback"), &PhysicsServer2D::area_set_area_monitor_callback); ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &PhysicsServer2D::area_set_monitorable); ClassDB::bind_method(D_METHOD("body_create"), &PhysicsServer2D::body_create); @@ -583,12 +651,10 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer2D::body_add_shape, DEFVAL(Transform2D()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer2D::body_set_shape); ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer2D::body_set_shape_transform); - ClassDB::bind_method(D_METHOD("body_set_shape_metadata", "body", "shape_idx", "metadata"), &PhysicsServer2D::body_set_shape_metadata); ClassDB::bind_method(D_METHOD("body_get_shape_count", "body"), &PhysicsServer2D::body_get_shape_count); ClassDB::bind_method(D_METHOD("body_get_shape", "body", "shape_idx"), &PhysicsServer2D::body_get_shape); ClassDB::bind_method(D_METHOD("body_get_shape_transform", "body", "shape_idx"), &PhysicsServer2D::body_get_shape_transform); - ClassDB::bind_method(D_METHOD("body_get_shape_metadata", "body", "shape_idx"), &PhysicsServer2D::body_get_shape_metadata); ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &PhysicsServer2D::body_remove_shape); ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &PhysicsServer2D::body_clear_shapes); @@ -614,6 +680,8 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer2D::body_set_param); ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer2D::body_get_param); + ClassDB::bind_method(D_METHOD("body_reset_mass_properties", "body"), &PhysicsServer2D::body_reset_mass_properties); + ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer2D::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer2D::body_get_state); @@ -636,7 +704,7 @@ void PhysicsServer2D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_force_integration_callback", "body", "callable", "userdata"), &PhysicsServer2D::body_set_force_integration_callback, DEFVAL(Variant())); - ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "margin", "result", "collide_separation_ray", "exclude"), &PhysicsServer2D::_body_test_motion, DEFVAL(0.08), DEFVAL(Variant()), DEFVAL(false), DEFVAL(Array())); + ClassDB::bind_method(D_METHOD("body_test_motion", "body", "parameters", "result"), &PhysicsServer2D::_body_test_motion, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer2D::body_get_direct_state); @@ -673,9 +741,8 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); - BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); - BIND_ENUM_CONSTANT(SHAPE_WORLD_MARGIN); + BIND_ENUM_CONSTANT(SHAPE_WORLD_BOUNDARY); BIND_ENUM_CONSTANT(SHAPE_SEPARATION_RAY); BIND_ENUM_CONSTANT(SHAPE_SEGMENT); BIND_ENUM_CONSTANT(SHAPE_CIRCLE); @@ -685,12 +752,15 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(SHAPE_CONCAVE_POLYGON); BIND_ENUM_CONSTANT(SHAPE_CUSTOM); + BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_OVERRIDE_MODE); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_VECTOR); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_IS_POINT); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_DISTANCE_SCALE); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_POINT_ATTENUATION); + BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE); BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP); + BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE); BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP); BIND_ENUM_CONSTANT(AREA_PARAM_PRIORITY); @@ -703,17 +773,23 @@ void PhysicsServer2D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_MODE_STATIC); BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC); BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC); - BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LOCKED); + BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LINEAR); BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE); BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION); BIND_ENUM_CONSTANT(BODY_PARAM_MASS); BIND_ENUM_CONSTANT(BODY_PARAM_INERTIA); + BIND_ENUM_CONSTANT(BODY_PARAM_CENTER_OF_MASS); BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE); + BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP_MODE); + BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP_MODE); BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP); BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP); BIND_ENUM_CONSTANT(BODY_PARAM_MAX); + BIND_ENUM_CONSTANT(BODY_DAMP_MODE_COMBINE); + BIND_ENUM_CONSTANT(BODY_DAMP_MODE_REPLACE); + BIND_ENUM_CONSTANT(BODY_STATE_TRANSFORM); BIND_ENUM_CONSTANT(BODY_STATE_LINEAR_VELOCITY); BIND_ENUM_CONSTANT(BODY_STATE_ANGULAR_VELOCITY); diff --git a/servers/physics_server_2d.h b/servers/physics_server_2d.h index 021d7be7c0..2bff8f5dcb 100644 --- a/servers/physics_server_2d.h +++ b/servers/physics_server_2d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PHYSICS_2D_SERVER_H -#define PHYSICS_2D_SERVER_H +#ifndef PHYSICS_SERVER_2D_H +#define PHYSICS_SERVER_2D_H #include "core/io/resource.h" #include "core/object/class_db.h" @@ -48,6 +48,8 @@ public: virtual real_t get_total_linear_damp() const = 0; // get density of this body space/area virtual real_t get_total_angular_damp() const = 0; // get density of this body space/area + virtual Vector2 get_center_of_mass() const = 0; + virtual Vector2 get_center_of_mass_local() const = 0; virtual real_t get_inverse_mass() const = 0; // get the mass virtual real_t get_inverse_inertia() const = 0; // get density of this body space @@ -83,7 +85,6 @@ public: virtual ObjectID get_contact_collider_id(int p_contact_idx) const = 0; virtual Object *get_contact_collider_object(int p_contact_idx) const; virtual int get_contact_collider_shape(int p_contact_idx) const = 0; - virtual Variant get_contact_collider_shape_metadata(int p_contact_idx) const = 0; virtual Vector2 get_contact_collider_velocity_at_position(int p_contact_idx) const = 0; virtual real_t get_step() const = 0; @@ -94,62 +95,15 @@ public: PhysicsDirectBodyState2D(); }; -//used for script -class PhysicsShapeQueryParameters2D : public RefCounted { - GDCLASS(PhysicsShapeQueryParameters2D, RefCounted); - friend class PhysicsDirectSpaceState2D; - - RES shape_ref; - RID shape; - Transform2D transform; - Vector2 motion; - real_t margin; - Set<RID> exclude; - uint32_t collision_mask; - - bool collide_with_bodies; - bool collide_with_areas; - -protected: - static void _bind_methods(); - -public: - void set_shape(const RES &p_shape_ref); - RES get_shape() const; - void set_shape_rid(const RID &p_shape); - RID get_shape_rid() const; - - void set_transform(const Transform2D &p_transform); - Transform2D get_transform() const; - - void set_motion(const Vector2 &p_motion); - Vector2 get_motion() const; - - void set_margin(real_t p_margin); - real_t get_margin() const; - - void set_collision_mask(uint32_t p_mask); - uint32_t get_collision_mask() const; - - void set_collide_with_bodies(bool p_enable); - bool is_collide_with_bodies_enabled() const; - - void set_collide_with_areas(bool p_enable); - bool is_collide_with_areas_enabled() const; - - void set_exclude(const Vector<RID> &p_exclude); - Vector<RID> get_exclude() const; - - PhysicsShapeQueryParameters2D(); -}; +class PhysicsRayQueryParameters2D; +class PhysicsPointQueryParameters2D; +class PhysicsShapeQueryParameters2D; class PhysicsDirectSpaceState2D : public Object { GDCLASS(PhysicsDirectSpaceState2D, 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 = ObjectID()); + Dictionary _intersect_ray(const Ref<PhysicsRayQueryParameters2D> &p_ray_query); + Array _intersect_point(const Ref<PhysicsPointQueryParameters2D> &p_point_query, int p_max_results = 32); Array _intersect_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32); Array _cast_motion(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query); Array _collide_shape(const Ref<PhysicsShapeQueryParameters2D> &p_shape_query, int p_max_results = 32); @@ -159,6 +113,18 @@ protected: static void _bind_methods(); public: + struct RayParameters { + Vector2 from; + Vector2 to; + Set<RID> exclude; + uint32_t collision_mask = UINT32_MAX; + + bool collide_with_bodies = true; + bool collide_with_areas = false; + + bool hit_from_inside = false; + }; + struct RayResult { Vector2 position; Vector2 normal; @@ -166,27 +132,42 @@ public: ObjectID collider_id; Object *collider = nullptr; int shape = 0; - Variant metadata; }; - 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_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual bool intersect_ray(const RayParameters &p_parameters, RayResult &r_result) = 0; struct ShapeResult { RID rid; ObjectID collider_id; Object *collider = nullptr; int shape = 0; - Variant metadata; }; - 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; + struct PointParameters { + Vector2 position; + ObjectID canvas_instance_id; + Set<RID> exclude; + uint32_t collision_mask = UINT32_MAX; + + bool collide_with_bodies = true; + bool collide_with_areas = false; + + bool pick_point = 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_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual int intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) = 0; - 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_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + struct ShapeParameters { + RID shape_rid; + Transform2D transform; + Vector2 motion; + real_t margin = 0.0; + Set<RID> exclude; + uint32_t collision_mask = UINT32_MAX; - virtual bool collide_shape(RID p_shape, const Transform2D &p_shape_xform, const Vector2 &p_motion, real_t p_margin, Vector2 *r_results, int p_result_max, int &r_result_count, 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; + bool collide_with_bodies = true; + bool collide_with_areas = false; + }; struct ShapeRestInfo { Vector2 point; @@ -194,15 +175,18 @@ public: RID rid; ObjectID collider_id; int shape = 0; - Vector2 linear_velocity; //velocity at contact point - Variant metadata; + Vector2 linear_velocity; // Velocity at contact point. }; - virtual bool 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 = Set<RID>(), uint32_t p_collision_layer = 0xFFFFFFFF, bool p_collide_with_bodies = true, bool p_collide_with_areas = false) = 0; + virtual int intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) = 0; + virtual bool cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe) = 0; + virtual bool collide_shape(const ShapeParameters &p_parameters, Vector2 *r_results, int p_result_max, int &r_result_count) = 0; + virtual bool rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) = 0; PhysicsDirectSpaceState2D(); }; +class PhysicsTestMotionParameters2D; class PhysicsTestMotionResult2D; class PhysicsServer2D : public Object { @@ -210,7 +194,7 @@ class PhysicsServer2D : public Object { static PhysicsServer2D *singleton; - virtual bool _body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>(), bool p_collide_separation_ray = false, const Vector<RID> &p_exclude = Vector<RID>()); + virtual bool _body_test_motion(RID p_body, const Ref<PhysicsTestMotionParameters2D> &p_parameters, const Ref<PhysicsTestMotionResult2D> &p_result = Ref<PhysicsTestMotionResult2D>()); protected: static void _bind_methods(); @@ -219,7 +203,7 @@ public: static PhysicsServer2D *get_singleton(); enum ShapeType { - SHAPE_WORLD_MARGIN, ///< plane:"plane" + SHAPE_WORLD_BOUNDARY, ///< plane:"plane" SHAPE_SEPARATION_RAY, ///< float:"length" SHAPE_SEGMENT, ///< float:"length" SHAPE_CIRCLE, ///< float:"radius" @@ -230,7 +214,7 @@ public: SHAPE_CUSTOM, ///< Server-Implementation based custom shape, calling shape_create() with this value will result in an error }; - virtual RID world_margin_shape_create() = 0; + virtual RID world_boundary_shape_create() = 0; virtual RID separation_ray_shape_create() = 0; virtual RID segment_shape_create() = 0; virtual RID circle_shape_create() = 0; @@ -263,7 +247,6 @@ public: SPACE_PARAM_BODY_ANGULAR_VELOCITY_SLEEP_THRESHOLD, SPACE_PARAM_BODY_TIME_TO_SLEEP, SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS, - SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH, }; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0; @@ -283,12 +266,15 @@ public: //missing attenuation? missing better override? enum AreaParameter { + AREA_PARAM_GRAVITY_OVERRIDE_MODE, AREA_PARAM_GRAVITY, AREA_PARAM_GRAVITY_VECTOR, AREA_PARAM_GRAVITY_IS_POINT, AREA_PARAM_GRAVITY_DISTANCE_SCALE, AREA_PARAM_GRAVITY_POINT_ATTENUATION, + AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE, AREA_PARAM_LINEAR_DAMP, + AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE, AREA_PARAM_ANGULAR_DAMP, AREA_PARAM_PRIORITY }; @@ -306,9 +292,6 @@ public: AREA_SPACE_OVERRIDE_REPLACE_COMBINE // Discards all previous calculations, then keeps combining }; - virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0; - virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0; - virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0; virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0; virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) = 0; @@ -340,8 +323,8 @@ public: virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0; virtual void area_set_pickable(RID p_area, bool p_pickable) = 0; - virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0; - virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0; + virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) = 0; + virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) = 0; /* BODY API */ @@ -351,7 +334,7 @@ public: BODY_MODE_STATIC, BODY_MODE_KINEMATIC, BODY_MODE_DYNAMIC, - BODY_MODE_DYNAMIC_LOCKED, + BODY_MODE_DYNAMIC_LINEAR, }; virtual RID body_create() = 0; @@ -365,12 +348,10 @@ public: virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0; virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0; virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) = 0; - virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) = 0; virtual int body_get_shape_count(RID p_body) const = 0; virtual RID body_get_shape(RID p_body, int p_shape_idx) const = 0; virtual Transform2D body_get_shape_transform(RID p_body, int p_shape_idx) const = 0; - virtual Variant body_get_shape_metadata(RID p_body, int p_shape_idx) const = 0; virtual void body_set_shape_disabled(RID p_body, int p_shape, bool p_disabled) = 0; virtual void body_set_shape_as_one_way_collision(RID p_body, int p_shape, bool p_enabled, real_t p_margin = 0) = 0; @@ -404,15 +385,25 @@ public: BODY_PARAM_BOUNCE, BODY_PARAM_FRICTION, BODY_PARAM_MASS, ///< unused for static, always infinite - BODY_PARAM_INERTIA, // read-only: computed from mass & shapes + BODY_PARAM_INERTIA, + BODY_PARAM_CENTER_OF_MASS, BODY_PARAM_GRAVITY_SCALE, + BODY_PARAM_LINEAR_DAMP_MODE, + BODY_PARAM_ANGULAR_DAMP_MODE, BODY_PARAM_LINEAR_DAMP, BODY_PARAM_ANGULAR_DAMP, BODY_PARAM_MAX, }; - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0; + enum BodyDampMode { + BODY_DAMP_MODE_COMBINE, + BODY_DAMP_MODE_REPLACE, + }; + + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) = 0; + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const = 0; + + virtual void body_reset_mass_properties(RID p_body) = 0; //state enum BodyState { @@ -470,6 +461,22 @@ public: // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState2D *body_get_direct_state(RID p_body) = 0; + struct MotionParameters { + Transform2D from; + Vector2 motion; + real_t margin = 0.08; + bool collide_separation_ray = false; + Set<RID> exclude_bodies; + Set<ObjectID> exclude_objects; + + MotionParameters() {} + + MotionParameters(const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08) : + from(p_from), + motion(p_motion), + margin(p_margin) {} + }; + struct MotionResult { Vector2 travel; Vector2 remainder; @@ -484,26 +491,13 @@ public: ObjectID collider_id; RID collider; int collider_shape = 0; - Variant collider_metadata; real_t get_angle(Vector2 p_up_direction) const { return Math::acos(collision_normal.dot(p_up_direction)); } }; - virtual bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) = 0; - - struct SeparationResult { - real_t collision_depth; - Vector2 collision_point; - Vector2 collision_normal; - Vector2 collider_velocity; - int collision_local_shape; - ObjectID collider_id; - RID collider; - int collider_shape; - Variant collider_metadata; - }; + virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) = 0; /* JOINT API */ @@ -586,11 +580,144 @@ public: ~PhysicsServer2D(); }; +class PhysicsRayQueryParameters2D : public RefCounted { + GDCLASS(PhysicsRayQueryParameters2D, RefCounted); + + PhysicsDirectSpaceState2D::RayParameters parameters; + +protected: + static void _bind_methods(); + +public: + const PhysicsDirectSpaceState2D::RayParameters &get_parameters() const { return parameters; } + + void set_from(const Vector2 &p_from) { parameters.from = p_from; } + const Vector2 &get_from() const { return parameters.from; } + + void set_to(const Vector2 &p_to) { parameters.to = p_to; } + const Vector2 &get_to() const { return parameters.to; } + + void set_collision_mask(uint32_t p_mask) { parameters.collision_mask = p_mask; } + uint32_t get_collision_mask() const { return parameters.collision_mask; } + + void set_collide_with_bodies(bool p_enable) { parameters.collide_with_bodies = p_enable; } + bool is_collide_with_bodies_enabled() const { return parameters.collide_with_bodies; } + + void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; } + bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; } + + void set_hit_from_inside(bool p_enable) { parameters.hit_from_inside = p_enable; } + bool is_hit_from_inside_enabled() const { return parameters.hit_from_inside; } + + void set_exclude(const Vector<RID> &p_exclude); + Vector<RID> get_exclude() const; +}; + +class PhysicsPointQueryParameters2D : public RefCounted { + GDCLASS(PhysicsPointQueryParameters2D, RefCounted); + + PhysicsDirectSpaceState2D::PointParameters parameters; + +protected: + static void _bind_methods(); + +public: + const PhysicsDirectSpaceState2D::PointParameters &get_parameters() const { return parameters; } + + void set_position(const Vector2 &p_position) { parameters.position = p_position; } + const Vector2 &get_position() const { return parameters.position; } + + void set_canvas_instance_id(ObjectID p_canvas_instance_id) { parameters.canvas_instance_id = p_canvas_instance_id; } + ObjectID get_canvas_instance_id() const { return parameters.canvas_instance_id; } + + void set_collision_mask(uint32_t p_mask) { parameters.collision_mask = p_mask; } + uint32_t get_collision_mask() const { return parameters.collision_mask; } + + void set_collide_with_bodies(bool p_enable) { parameters.collide_with_bodies = p_enable; } + bool is_collide_with_bodies_enabled() const { return parameters.collide_with_bodies; } + + void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; } + bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; } + + void set_exclude(const Vector<RID> &p_exclude); + Vector<RID> get_exclude() const; +}; + +class PhysicsShapeQueryParameters2D : public RefCounted { + GDCLASS(PhysicsShapeQueryParameters2D, RefCounted); + + PhysicsDirectSpaceState2D::ShapeParameters parameters; + + RES shape_ref; + +protected: + static void _bind_methods(); + +public: + const PhysicsDirectSpaceState2D::ShapeParameters &get_parameters() const { return parameters; } + + void set_shape(const RES &p_shape_ref); + RES get_shape() const { return shape_ref; } + + void set_shape_rid(const RID &p_shape); + RID get_shape_rid() const { return parameters.shape_rid; } + + void set_transform(const Transform2D &p_transform) { parameters.transform = p_transform; } + const Transform2D &get_transform() const { return parameters.transform; } + + void set_motion(const Vector2 &p_motion) { parameters.motion = p_motion; } + const Vector2 &get_motion() const { return parameters.motion; } + + void set_margin(real_t p_margin) { parameters.margin = p_margin; } + real_t get_margin() const { return parameters.margin; } + + void set_collision_mask(uint32_t p_mask) { parameters.collision_mask = p_mask; } + uint32_t get_collision_mask() const { return parameters.collision_mask; } + + void set_collide_with_bodies(bool p_enable) { parameters.collide_with_bodies = p_enable; } + bool is_collide_with_bodies_enabled() const { return parameters.collide_with_bodies; } + + void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; } + bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; } + + void set_exclude(const Vector<RID> &p_exclude); + Vector<RID> get_exclude() const; +}; + +class PhysicsTestMotionParameters2D : public RefCounted { + GDCLASS(PhysicsTestMotionParameters2D, RefCounted); + + PhysicsServer2D::MotionParameters parameters; + +protected: + static void _bind_methods(); + +public: + const PhysicsServer2D::MotionParameters &get_parameters() const { return parameters; } + + const Transform2D &get_from() const { return parameters.from; } + void set_from(const Transform2D &p_from) { parameters.from = p_from; } + + const Vector2 &get_motion() const { return parameters.motion; } + void set_motion(const Vector2 &p_motion) { parameters.motion = p_motion; } + + real_t get_margin() const { return parameters.margin; } + void set_margin(real_t p_margin) { parameters.margin = p_margin; } + + bool is_collide_separation_ray_enabled() const { return parameters.collide_separation_ray; } + void set_collide_separation_ray_enabled(bool p_enabled) { parameters.collide_separation_ray = p_enabled; } + + Vector<RID> get_exclude_bodies() const; + void set_exclude_bodies(const Vector<RID> &p_exclude); + + Array get_exclude_objects() const; + void set_exclude_objects(const Array &p_exclude); +}; + class PhysicsTestMotionResult2D : public RefCounted { GDCLASS(PhysicsTestMotionResult2D, RefCounted); PhysicsServer2D::MotionResult result; - friend class PhysicsServer2D; protected: static void _bind_methods(); @@ -608,6 +735,7 @@ public: RID get_collider_rid() const; Object *get_collider() const; int get_collider_shape() const; + int get_collision_local_shape() const; real_t get_collision_depth() const; real_t get_collision_safe_fraction() const; real_t get_collision_unsafe_fraction() const; @@ -663,13 +791,13 @@ VARIANT_ENUM_CAST(PhysicsServer2D::AreaParameter); VARIANT_ENUM_CAST(PhysicsServer2D::AreaSpaceOverrideMode); VARIANT_ENUM_CAST(PhysicsServer2D::BodyMode); VARIANT_ENUM_CAST(PhysicsServer2D::BodyParameter); +VARIANT_ENUM_CAST(PhysicsServer2D::BodyDampMode); VARIANT_ENUM_CAST(PhysicsServer2D::BodyState); VARIANT_ENUM_CAST(PhysicsServer2D::CCDMode); VARIANT_ENUM_CAST(PhysicsServer2D::JointParam); VARIANT_ENUM_CAST(PhysicsServer2D::JointType); VARIANT_ENUM_CAST(PhysicsServer2D::DampedSpringParam); -//VARIANT_ENUM_CAST( PhysicsServer2D::ObjectType ); VARIANT_ENUM_CAST(PhysicsServer2D::AreaBodyStatus); VARIANT_ENUM_CAST(PhysicsServer2D::ProcessInfo); -#endif +#endif // PHYSICS_SERVER_2D_H diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.cpp b/servers/physics_server_2d_wrap_mt.cpp index 930b19c2cb..33070bf42d 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.cpp +++ b/servers/physics_server_2d_wrap_mt.cpp @@ -119,7 +119,6 @@ PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool command_queue(p_create_thread) { physics_2d_server = p_contained; create_thread = p_create_thread; - step_pending = 0; pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); @@ -130,7 +129,6 @@ PhysicsServer2DWrapMT::PhysicsServer2DWrapMT(PhysicsServer2D *p_contained, bool } main_thread = Thread::get_caller_id(); - first_frame = true; } PhysicsServer2DWrapMT::~PhysicsServer2DWrapMT() { diff --git a/servers/physics_2d/physics_server_2d_wrap_mt.h b/servers/physics_server_2d_wrap_mt.h index 6761e37daa..dda4eb6ffa 100644 --- a/servers/physics_2d/physics_server_2d_wrap_mt.h +++ b/servers/physics_server_2d_wrap_mt.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PHYSICS2DSERVERWRAPMT_H -#define PHYSICS2DSERVERWRAPMT_H +#ifndef PHYSICS_SERVER_2D_WRAP_MT_H +#define PHYSICS_SERVER_2D_WRAP_MT_H #include "core/config/project_settings.h" #include "core/os/thread.h" @@ -56,19 +56,17 @@ class PhysicsServer2DWrapMT : public PhysicsServer2D { SafeFlag exit; Thread thread; SafeFlag step_thread_up; - bool create_thread; + bool create_thread = false; Semaphore step_sem; - int step_pending; void thread_step(real_t p_delta); - void thread_flush(); void thread_exit(); - bool first_frame; + bool first_frame = true; Mutex alloc_mutex; - int pool_max_size; + int pool_max_size = 0; public: #define ServerName PhysicsServer2D @@ -79,7 +77,7 @@ public: #include "servers/server_wrap_mt_common.h" //FUNC1RID(shape,ShapeType); todo fix - FUNCRID(world_margin_shape) + FUNCRID(world_boundary_shape) FUNCRID(separation_ray_shape) FUNCRID(segment_shape) FUNCRID(circle_shape) @@ -135,9 +133,6 @@ public: FUNC2(area_set_space, RID, RID); FUNC1RC(RID, area_get_space, RID); - FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode); - FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID); - FUNC4(area_add_shape, RID, RID, const Transform2D &, bool); FUNC3(area_set_shape, RID, int, RID); FUNC3(area_set_shape_transform, RID, int, const Transform2D &); @@ -167,8 +162,8 @@ public: FUNC2(area_set_monitorable, RID, bool); FUNC2(area_set_pickable, RID, bool); - FUNC3(area_set_monitor_callback, RID, Object *, const StringName &); - FUNC3(area_set_area_monitor_callback, RID, Object *, const StringName &); + FUNC2(area_set_monitor_callback, RID, const Callable &); + FUNC2(area_set_area_monitor_callback, RID, const Callable &); /* BODY API */ @@ -184,11 +179,9 @@ public: FUNC4(body_add_shape, RID, RID, const Transform2D &, bool); FUNC3(body_set_shape, RID, int, RID); FUNC3(body_set_shape_transform, RID, int, const Transform2D &); - FUNC3(body_set_shape_metadata, RID, int, const Variant &); FUNC1RC(int, body_get_shape_count, RID); FUNC2RC(Transform2D, body_get_shape_transform, RID, int); - FUNC2RC(Variant, body_get_shape_metadata, RID, int); FUNC2RC(RID, body_get_shape, RID, int); FUNC3(body_set_shape_disabled, RID, int, bool); @@ -212,8 +205,10 @@ public: FUNC2(body_set_collision_mask, RID, uint32_t); FUNC1RC(uint32_t, body_get_collision_mask, RID); - FUNC3(body_set_param, RID, BodyParameter, real_t); - FUNC2RC(real_t, body_get_param, RID, BodyParameter); + FUNC3(body_set_param, RID, BodyParameter, const Variant &); + FUNC2RC(Variant, body_get_param, RID, BodyParameter); + + FUNC1(body_reset_mass_properties, RID); FUNC3(body_set_state, RID, BodyState, const Variant &); FUNC2RC(Variant, body_get_state, RID, BodyState); @@ -254,9 +249,9 @@ public: FUNC2(body_set_pickable, RID, bool); - bool body_test_motion(RID p_body, const Transform2D &p_from, const Vector2 &p_motion, real_t p_margin = 0.08, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override { + bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); - return physics_2d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result, p_collide_separation_ray, p_exclude); + return physics_2d_server->body_test_motion(p_body, p_parameters, r_result); } // this function only works on physics process, errors and returns null otherwise @@ -330,4 +325,4 @@ public: #endif #undef SYNC_DEBUG -#endif // PHYSICS2DSERVERWRAPMT_H +#endif // PHYSICS_SERVER_2D_WRAP_MT_H diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 6cde4977f4..373f216e01 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -77,6 +77,7 @@ void PhysicsDirectBodyState3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_total_angular_damp"), &PhysicsDirectBodyState3D::get_total_angular_damp); ClassDB::bind_method(D_METHOD("get_center_of_mass"), &PhysicsDirectBodyState3D::get_center_of_mass); + ClassDB::bind_method(D_METHOD("get_center_of_mass_local"), &PhysicsDirectBodyState3D::get_center_of_mass_local); ClassDB::bind_method(D_METHOD("get_principal_inertia_axes"), &PhysicsDirectBodyState3D::get_principal_inertia_axes); ClassDB::bind_method(D_METHOD("get_inverse_mass"), &PhysicsDirectBodyState3D::get_inverse_mass); @@ -126,6 +127,7 @@ void PhysicsDirectBodyState3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "inverse_inertia"), "", "get_inverse_inertia"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "total_gravity"), "", "get_total_gravity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass"), "", "get_center_of_mass"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "center_of_mass_local"), "", "get_center_of_mass_local"); ADD_PROPERTY(PropertyInfo(Variant::BASIS, "principal_inertia_axes"), "", "get_principal_inertia_axes"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); @@ -137,93 +139,145 @@ PhysicsDirectBodyState3D::PhysicsDirectBodyState3D() {} /////////////////////////////////////////////////////// -void PhysicsShapeQueryParameters3D::set_shape(const RES &p_shape_ref) { - ERR_FAIL_COND(p_shape_ref.is_null()); - shape_ref = p_shape_ref; - shape = p_shape_ref->get_rid(); -} - -RES PhysicsShapeQueryParameters3D::get_shape() const { - return shape_ref; +void PhysicsRayQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) { + parameters.exclude.clear(); + for (int i = 0; i < p_exclude.size(); i++) { + parameters.exclude.insert(p_exclude[i]); + } } -void PhysicsShapeQueryParameters3D::set_shape_rid(const RID &p_shape) { - if (shape != p_shape) { - shape_ref = RES(); - shape = p_shape; +Vector<RID> PhysicsRayQueryParameters3D::get_exclude() const { + Vector<RID> ret; + ret.resize(parameters.exclude.size()); + int idx = 0; + for (Set<RID>::Element *E = parameters.exclude.front(); E; E = E->next()) { + ret.write[idx++] = E->get(); } + return ret; } -RID PhysicsShapeQueryParameters3D::get_shape_rid() const { - return shape; -} +void PhysicsRayQueryParameters3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_from", "from"), &PhysicsRayQueryParameters3D::set_from); + ClassDB::bind_method(D_METHOD("get_from"), &PhysicsRayQueryParameters3D::get_from); -void PhysicsShapeQueryParameters3D::set_transform(const Transform3D &p_transform) { - transform = p_transform; -} + ClassDB::bind_method(D_METHOD("set_to", "to"), &PhysicsRayQueryParameters3D::set_to); + ClassDB::bind_method(D_METHOD("get_to"), &PhysicsRayQueryParameters3D::get_to); -Transform3D PhysicsShapeQueryParameters3D::get_transform() const { - return transform; -} + ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &PhysicsRayQueryParameters3D::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsRayQueryParameters3D::get_collision_mask); -void PhysicsShapeQueryParameters3D::set_margin(real_t p_margin) { - margin = p_margin; -} + ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &PhysicsRayQueryParameters3D::set_exclude); + ClassDB::bind_method(D_METHOD("get_exclude"), &PhysicsRayQueryParameters3D::get_exclude); -real_t PhysicsShapeQueryParameters3D::get_margin() const { - return margin; -} + ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &PhysicsRayQueryParameters3D::set_collide_with_bodies); + ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &PhysicsRayQueryParameters3D::is_collide_with_bodies_enabled); -void PhysicsShapeQueryParameters3D::set_collision_mask(uint32_t p_collision_mask) { - collision_mask = p_collision_mask; -} + ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsRayQueryParameters3D::set_collide_with_areas); + ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsRayQueryParameters3D::is_collide_with_areas_enabled); + + ClassDB::bind_method(D_METHOD("set_hit_from_inside", "enable"), &PhysicsRayQueryParameters3D::set_hit_from_inside); + ClassDB::bind_method(D_METHOD("is_hit_from_inside_enabled"), &PhysicsRayQueryParameters3D::is_hit_from_inside_enabled); -uint32_t PhysicsShapeQueryParameters3D::get_collision_mask() const { - return collision_mask; + ClassDB::bind_method(D_METHOD("set_hit_back_faces", "enable"), &PhysicsRayQueryParameters3D::set_hit_back_faces); + ClassDB::bind_method(D_METHOD("is_hit_back_faces_enabled"), &PhysicsRayQueryParameters3D::is_hit_back_faces_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "from"), "set_from", "get_from"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "to"), "set_to", "get_to"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_from_inside"), "set_hit_from_inside", "is_hit_from_inside_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "hit_back_faces"), "set_hit_back_faces", "is_hit_back_faces_enabled"); } -void PhysicsShapeQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) { - exclude.clear(); +/////////////////////////////////////////////////////// + +void PhysicsPointQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) { + parameters.exclude.clear(); for (int i = 0; i < p_exclude.size(); i++) { - exclude.insert(p_exclude[i]); + parameters.exclude.insert(p_exclude[i]); } } -Vector<RID> PhysicsShapeQueryParameters3D::get_exclude() const { +Vector<RID> PhysicsPointQueryParameters3D::get_exclude() const { Vector<RID> ret; - ret.resize(exclude.size()); + ret.resize(parameters.exclude.size()); int idx = 0; - for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) { - ret.write[idx] = E->get(); + for (Set<RID>::Element *E = parameters.exclude.front(); E; E = E->next()) { + ret.write[idx++] = E->get(); } return ret; } -void PhysicsShapeQueryParameters3D::set_collide_with_bodies(bool p_enable) { - collide_with_bodies = p_enable; +void PhysicsPointQueryParameters3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_position", "position"), &PhysicsPointQueryParameters3D::set_position); + ClassDB::bind_method(D_METHOD("get_position"), &PhysicsPointQueryParameters3D::get_position); + + ClassDB::bind_method(D_METHOD("set_collision_mask", "collision_mask"), &PhysicsPointQueryParameters3D::set_collision_mask); + ClassDB::bind_method(D_METHOD("get_collision_mask"), &PhysicsPointQueryParameters3D::get_collision_mask); + + ClassDB::bind_method(D_METHOD("set_exclude", "exclude"), &PhysicsPointQueryParameters3D::set_exclude); + ClassDB::bind_method(D_METHOD("get_exclude"), &PhysicsPointQueryParameters3D::get_exclude); + + ClassDB::bind_method(D_METHOD("set_collide_with_bodies", "enable"), &PhysicsPointQueryParameters3D::set_collide_with_bodies); + ClassDB::bind_method(D_METHOD("is_collide_with_bodies_enabled"), &PhysicsPointQueryParameters3D::is_collide_with_bodies_enabled); + + ClassDB::bind_method(D_METHOD("set_collide_with_areas", "enable"), &PhysicsPointQueryParameters3D::set_collide_with_areas); + ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsPointQueryParameters3D::is_collide_with_areas_enabled); + + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "position"), "set_position", "get_position"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_bodies"), "set_collide_with_bodies", "is_collide_with_bodies_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); } -bool PhysicsShapeQueryParameters3D::is_collide_with_bodies_enabled() const { - return collide_with_bodies; +/////////////////////////////////////////////////////// + +void PhysicsShapeQueryParameters3D::set_shape(const RES &p_shape_ref) { + ERR_FAIL_COND(p_shape_ref.is_null()); + shape_ref = p_shape_ref; + parameters.shape_rid = p_shape_ref->get_rid(); } -void PhysicsShapeQueryParameters3D::set_collide_with_areas(bool p_enable) { - collide_with_areas = p_enable; +void PhysicsShapeQueryParameters3D::set_shape_rid(const RID &p_shape) { + if (parameters.shape_rid != p_shape) { + shape_ref = RES(); + parameters.shape_rid = p_shape; + } } -bool PhysicsShapeQueryParameters3D::is_collide_with_areas_enabled() const { - return collide_with_areas; +void PhysicsShapeQueryParameters3D::set_exclude(const Vector<RID> &p_exclude) { + parameters.exclude.clear(); + for (int i = 0; i < p_exclude.size(); i++) { + parameters.exclude.insert(p_exclude[i]); + } +} + +Vector<RID> PhysicsShapeQueryParameters3D::get_exclude() const { + Vector<RID> ret; + ret.resize(parameters.exclude.size()); + int idx = 0; + for (Set<RID>::Element *E = parameters.exclude.front(); E; E = E->next()) { + ret.write[idx++] = E->get(); + } + return ret; } void PhysicsShapeQueryParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("set_shape", "shape"), &PhysicsShapeQueryParameters3D::set_shape); ClassDB::bind_method(D_METHOD("get_shape"), &PhysicsShapeQueryParameters3D::get_shape); + ClassDB::bind_method(D_METHOD("set_shape_rid", "shape"), &PhysicsShapeQueryParameters3D::set_shape_rid); ClassDB::bind_method(D_METHOD("get_shape_rid"), &PhysicsShapeQueryParameters3D::get_shape_rid); ClassDB::bind_method(D_METHOD("set_transform", "transform"), &PhysicsShapeQueryParameters3D::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &PhysicsShapeQueryParameters3D::get_transform); + ClassDB::bind_method(D_METHOD("set_motion", "motion"), &PhysicsShapeQueryParameters3D::set_motion); + ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsShapeQueryParameters3D::get_motion); + ClassDB::bind_method(D_METHOD("set_margin", "margin"), &PhysicsShapeQueryParameters3D::set_margin); ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsShapeQueryParameters3D::get_margin); @@ -240,8 +294,9 @@ void PhysicsShapeQueryParameters3D::_bind_methods() { ClassDB::bind_method(D_METHOD("is_collide_with_areas_enabled"), &PhysicsShapeQueryParameters3D::is_collide_with_areas_enabled); ADD_PROPERTY(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS), "set_collision_mask", "get_collision_mask"); - ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_NONE, itos(Variant::RID) + ":"), "set_exclude", "get_exclude"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude", "get_exclude"); ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin", PROPERTY_HINT_RANGE, "0,100,0.01"), "set_margin", "get_margin"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR2, "motion"), "set_motion", "get_motion"); ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "shape", PROPERTY_HINT_RESOURCE_TYPE, "Shape3D"), "set_shape", "get_shape"); ADD_PROPERTY(PropertyInfo(Variant::RID, "shape_rid"), "set_shape_rid", "get_shape_rid"); ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "transform"), "set_transform", "get_transform"); @@ -249,45 +304,58 @@ void PhysicsShapeQueryParameters3D::_bind_methods() { ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_with_areas"), "set_collide_with_areas", "is_collide_with_areas_enabled"); } -PhysicsShapeQueryParameters3D::PhysicsShapeQueryParameters3D() { - margin = 0; - collision_mask = 0x7FFFFFFF; - collide_with_bodies = true; - collide_with_areas = false; -} - ///////////////////////////////////// -Dictionary PhysicsDirectSpaceState3D::_intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude, uint32_t p_collision_mask, bool p_collide_with_bodies, bool p_collide_with_areas) { - RayResult inters; - Set<RID> exclude; - for (int i = 0; i < p_exclude.size(); i++) { - exclude.insert(p_exclude[i]); - } +Dictionary PhysicsDirectSpaceState3D::_intersect_ray(const Ref<PhysicsRayQueryParameters3D> &p_ray_query) { + ERR_FAIL_COND_V(!p_ray_query.is_valid(), Dictionary()); - bool res = intersect_ray(p_from, p_to, inters, exclude, p_collision_mask, p_collide_with_bodies, p_collide_with_areas); + RayResult result; + bool res = intersect_ray(p_ray_query->get_parameters(), result); if (!res) { return Dictionary(); } Dictionary d; - d["position"] = inters.position; - d["normal"] = inters.normal; - d["collider_id"] = inters.collider_id; - d["collider"] = inters.collider; - d["shape"] = inters.shape; - d["rid"] = inters.rid; + d["position"] = result.position; + d["normal"] = result.normal; + d["collider_id"] = result.collider_id; + d["collider"] = result.collider; + d["shape"] = result.shape; + d["rid"] = result.rid; return d; } +Array PhysicsDirectSpaceState3D::_intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results) { + Vector<ShapeResult> ret; + ret.resize(p_max_results); + + int rc = intersect_point(p_point_query->get_parameters(), ret.ptrw(), ret.size()); + + if (rc == 0) { + return Array(); + } + + Array r; + r.resize(rc); + for (int i = 0; i < rc; i++) { + Dictionary d; + d["rid"] = ret[i].rid; + d["collider_id"] = ret[i].collider_id; + d["collider"] = ret[i].collider; + d["shape"] = ret[i].shape; + r[i] = d; + } + return r; +} + Array PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); Vector<ShapeResult> sr; sr.resize(p_max_results); - int rc = intersect_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, sr.ptrw(), sr.size(), p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); + int rc = intersect_shape(p_shape_query->get_parameters(), sr.ptrw(), sr.size()); Array ret; ret.resize(rc); for (int i = 0; i < rc; i++) { @@ -302,11 +370,11 @@ Array PhysicsDirectSpaceState3D::_intersect_shape(const Ref<PhysicsShapeQueryPar return ret; } -Array PhysicsDirectSpaceState3D::_cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, const Vector3 &p_motion) { +Array PhysicsDirectSpaceState3D::_cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query) { ERR_FAIL_COND_V(!p_shape_query.is_valid(), Array()); real_t closest_safe = 1.0f, closest_unsafe = 1.0f; - bool res = cast_motion(p_shape_query->shape, p_shape_query->transform, p_motion, p_shape_query->margin, closest_safe, closest_unsafe, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); + bool res = cast_motion(p_shape_query->get_parameters(), closest_safe, closest_unsafe); if (!res) { return Array(); } @@ -323,7 +391,7 @@ Array PhysicsDirectSpaceState3D::_collide_shape(const Ref<PhysicsShapeQueryParam Vector<Vector3> ret; ret.resize(p_max_results * 2); int rc = 0; - bool res = collide_shape(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, ret.ptrw(), p_max_results, rc, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); + bool res = collide_shape(p_shape_query->get_parameters(), ret.ptrw(), p_max_results, rc); if (!res) { return Array(); } @@ -340,7 +408,7 @@ Dictionary PhysicsDirectSpaceState3D::_get_rest_info(const Ref<PhysicsShapeQuery ShapeRestInfo sri; - bool res = rest_info(p_shape_query->shape, p_shape_query->transform, p_shape_query->margin, &sri, p_shape_query->exclude, p_shape_query->collision_mask, p_shape_query->collide_with_bodies, p_shape_query->collide_with_areas); + bool res = rest_info(p_shape_query->get_parameters(), &sri); Dictionary r; if (!res) { return r; @@ -360,11 +428,83 @@ PhysicsDirectSpaceState3D::PhysicsDirectSpaceState3D() { } void PhysicsDirectSpaceState3D::_bind_methods() { - ClassDB::bind_method(D_METHOD("intersect_ray", "from", "to", "exclude", "collision_mask", "collide_with_bodies", "collide_with_areas"), &PhysicsDirectSpaceState3D::_intersect_ray, DEFVAL(Array()), DEFVAL(0x7FFFFFFF), DEFVAL(true), DEFVAL(false)); - ClassDB::bind_method(D_METHOD("intersect_shape", "shape", "max_results"), &PhysicsDirectSpaceState3D::_intersect_shape, DEFVAL(32)); - ClassDB::bind_method(D_METHOD("cast_motion", "shape", "motion"), &PhysicsDirectSpaceState3D::_cast_motion); - ClassDB::bind_method(D_METHOD("collide_shape", "shape", "max_results"), &PhysicsDirectSpaceState3D::_collide_shape, DEFVAL(32)); - ClassDB::bind_method(D_METHOD("get_rest_info", "shape"), &PhysicsDirectSpaceState3D::_get_rest_info); + ClassDB::bind_method(D_METHOD("intersect_point", "parameters", "max_results"), &PhysicsDirectSpaceState3D::_intersect_point, DEFVAL(32)); + ClassDB::bind_method(D_METHOD("intersect_ray", "parameters"), &PhysicsDirectSpaceState3D::_intersect_ray); + ClassDB::bind_method(D_METHOD("intersect_shape", "parameters", "max_results"), &PhysicsDirectSpaceState3D::_intersect_shape, DEFVAL(32)); + ClassDB::bind_method(D_METHOD("cast_motion", "parameters"), &PhysicsDirectSpaceState3D::_cast_motion); + ClassDB::bind_method(D_METHOD("collide_shape", "parameters", "max_results"), &PhysicsDirectSpaceState3D::_collide_shape, DEFVAL(32)); + ClassDB::bind_method(D_METHOD("get_rest_info", "parameters"), &PhysicsDirectSpaceState3D::_get_rest_info); +} + +/////////////////////////////// + +Vector<RID> PhysicsTestMotionParameters3D::get_exclude_bodies() const { + Vector<RID> exclude; + exclude.resize(parameters.exclude_bodies.size()); + + int body_index = 0; + for (RID body : parameters.exclude_bodies) { + exclude.write[body_index++] = body; + } + + return exclude; +} + +void PhysicsTestMotionParameters3D::set_exclude_bodies(const Vector<RID> &p_exclude) { + for (RID body : p_exclude) { + parameters.exclude_bodies.insert(body); + } +} + +Array PhysicsTestMotionParameters3D::get_exclude_objects() const { + Array exclude; + exclude.resize(parameters.exclude_objects.size()); + + int object_index = 0; + for (ObjectID object_id : parameters.exclude_objects) { + exclude[object_index++] = object_id; + } + + return exclude; +} + +void PhysicsTestMotionParameters3D::set_exclude_objects(const Array &p_exclude) { + for (int i = 0; i < p_exclude.size(); ++i) { + ObjectID object_id = p_exclude[i]; + ERR_CONTINUE(object_id.is_null()); + parameters.exclude_objects.insert(object_id); + } +} + +void PhysicsTestMotionParameters3D::_bind_methods() { + ClassDB::bind_method(D_METHOD("get_from"), &PhysicsTestMotionParameters3D::get_from); + ClassDB::bind_method(D_METHOD("set_from", "from"), &PhysicsTestMotionParameters3D::set_from); + + ClassDB::bind_method(D_METHOD("get_motion"), &PhysicsTestMotionParameters3D::get_motion); + ClassDB::bind_method(D_METHOD("set_motion", "motion"), &PhysicsTestMotionParameters3D::set_motion); + + ClassDB::bind_method(D_METHOD("get_margin"), &PhysicsTestMotionParameters3D::get_margin); + ClassDB::bind_method(D_METHOD("set_margin", "margin"), &PhysicsTestMotionParameters3D::set_margin); + + ClassDB::bind_method(D_METHOD("get_max_collisions"), &PhysicsTestMotionParameters3D::get_max_collisions); + ClassDB::bind_method(D_METHOD("set_max_collisions", "max_collisions"), &PhysicsTestMotionParameters3D::set_max_collisions); + + ClassDB::bind_method(D_METHOD("is_collide_separation_ray_enabled"), &PhysicsTestMotionParameters3D::is_collide_separation_ray_enabled); + ClassDB::bind_method(D_METHOD("set_collide_separation_ray_enabled", "enabled"), &PhysicsTestMotionParameters3D::set_collide_separation_ray_enabled); + + ClassDB::bind_method(D_METHOD("get_exclude_bodies"), &PhysicsTestMotionParameters3D::get_exclude_bodies); + ClassDB::bind_method(D_METHOD("set_exclude_bodies", "exclude_list"), &PhysicsTestMotionParameters3D::set_exclude_bodies); + + ClassDB::bind_method(D_METHOD("get_exclude_objects"), &PhysicsTestMotionParameters3D::get_exclude_objects); + ClassDB::bind_method(D_METHOD("set_exclude_objects", "exclude_list"), &PhysicsTestMotionParameters3D::set_exclude_objects); + + ADD_PROPERTY(PropertyInfo(Variant::TRANSFORM3D, "from"), "set_from", "get_from"); + ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "motion"), "set_motion", "get_motion"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "margin"), "set_margin", "get_margin"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "max_collisions"), "set_max_collisions", "get_max_collisions"); + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "collide_separation_ray"), "set_collide_separation_ray_enabled", "is_collide_separation_ray_enabled"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_bodies", PROPERTY_HINT_ARRAY_TYPE, "RID"), "set_exclude_bodies", "get_exclude_bodies"); + ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "exclude_objects"), "set_exclude_objects", "get_exclude_objects"); } /////////////////////////////// @@ -377,92 +517,97 @@ Vector3 PhysicsTestMotionResult3D::get_remainder() const { return result.remainder; } -Vector3 PhysicsTestMotionResult3D::get_collision_point() const { - return result.collision_point; +real_t PhysicsTestMotionResult3D::get_collision_safe_fraction() const { + return result.collision_safe_fraction; } -Vector3 PhysicsTestMotionResult3D::get_collision_normal() const { - return result.collision_normal; +real_t PhysicsTestMotionResult3D::get_collision_unsafe_fraction() const { + return result.collision_unsafe_fraction; } -Vector3 PhysicsTestMotionResult3D::get_collider_velocity() const { - return result.collider_velocity; +int PhysicsTestMotionResult3D::get_collision_count() const { + return result.collision_count; } -ObjectID PhysicsTestMotionResult3D::get_collider_id() const { - return result.collider_id; +Vector3 PhysicsTestMotionResult3D::get_collision_point(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); + return result.collisions[p_collision_index].position; } -RID PhysicsTestMotionResult3D::get_collider_rid() const { - return result.collider; +Vector3 PhysicsTestMotionResult3D::get_collision_normal(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); + return result.collisions[p_collision_index].normal; } -Object *PhysicsTestMotionResult3D::get_collider() const { - return ObjectDB::get_instance(result.collider_id); +Vector3 PhysicsTestMotionResult3D::get_collider_velocity(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, Vector3()); + return result.collisions[p_collision_index].collider_velocity; } -int PhysicsTestMotionResult3D::get_collider_shape() const { - return result.collider_shape; +ObjectID PhysicsTestMotionResult3D::get_collider_id(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, ObjectID()); + return result.collisions[p_collision_index].collider_id; } -real_t PhysicsTestMotionResult3D::get_collision_depth() const { - return result.collision_depth; +RID PhysicsTestMotionResult3D::get_collider_rid(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, RID()); + return result.collisions[p_collision_index].collider; } -real_t PhysicsTestMotionResult3D::get_collision_safe_fraction() const { - return result.collision_safe_fraction; +Object *PhysicsTestMotionResult3D::get_collider(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, nullptr); + return ObjectDB::get_instance(result.collisions[p_collision_index].collider_id); } -real_t PhysicsTestMotionResult3D::get_collision_unsafe_fraction() const { - return result.collision_unsafe_fraction; +int PhysicsTestMotionResult3D::get_collider_shape(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0); + return result.collisions[p_collision_index].collider_shape; +} + +int PhysicsTestMotionResult3D::get_collision_local_shape(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0); + return result.collisions[p_collision_index].local_shape; +} + +real_t PhysicsTestMotionResult3D::get_collision_depth(int p_collision_index) const { + ERR_FAIL_INDEX_V(p_collision_index, result.collision_count, 0.0); + return result.collisions[p_collision_index].depth; } void PhysicsTestMotionResult3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_travel"), &PhysicsTestMotionResult3D::get_travel); ClassDB::bind_method(D_METHOD("get_remainder"), &PhysicsTestMotionResult3D::get_remainder); - ClassDB::bind_method(D_METHOD("get_collision_point"), &PhysicsTestMotionResult3D::get_collision_point); - ClassDB::bind_method(D_METHOD("get_collision_normal"), &PhysicsTestMotionResult3D::get_collision_normal); - ClassDB::bind_method(D_METHOD("get_collider_velocity"), &PhysicsTestMotionResult3D::get_collider_velocity); - ClassDB::bind_method(D_METHOD("get_collider_id"), &PhysicsTestMotionResult3D::get_collider_id); - ClassDB::bind_method(D_METHOD("get_collider_rid"), &PhysicsTestMotionResult3D::get_collider_rid); - ClassDB::bind_method(D_METHOD("get_collider"), &PhysicsTestMotionResult3D::get_collider); - ClassDB::bind_method(D_METHOD("get_collider_shape"), &PhysicsTestMotionResult3D::get_collider_shape); - ClassDB::bind_method(D_METHOD("get_collision_depth"), &PhysicsTestMotionResult3D::get_collision_depth); ClassDB::bind_method(D_METHOD("get_collision_safe_fraction"), &PhysicsTestMotionResult3D::get_collision_safe_fraction); ClassDB::bind_method(D_METHOD("get_collision_unsafe_fraction"), &PhysicsTestMotionResult3D::get_collision_unsafe_fraction); - - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "travel"), "", "get_travel"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "remainder"), "", "get_remainder"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_point"), "", "get_collision_point"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collision_normal"), "", "get_collision_normal"); - ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "collider_velocity"), "", "get_collider_velocity"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_id", PROPERTY_HINT_OBJECT_ID), "", "get_collider_id"); - ADD_PROPERTY(PropertyInfo(Variant::RID, "collider_rid"), "", "get_collider_rid"); - ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "collider"), "", "get_collider"); - ADD_PROPERTY(PropertyInfo(Variant::INT, "collider_shape"), "", "get_collider_shape"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_depth"), "", "get_collision_depth"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_safe_fraction"), "", "get_collision_safe_fraction"); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "collision_unsafe_fraction"), "", "get_collision_unsafe_fraction"); + ClassDB::bind_method(D_METHOD("get_collision_count"), &PhysicsTestMotionResult3D::get_collision_count); + ClassDB::bind_method(D_METHOD("get_collision_point", "collision_index"), &PhysicsTestMotionResult3D::get_collision_point, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collision_normal", "collision_index"), &PhysicsTestMotionResult3D::get_collision_normal, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_velocity", "collision_index"), &PhysicsTestMotionResult3D::get_collider_velocity, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_id", "collision_index"), &PhysicsTestMotionResult3D::get_collider_id, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_rid", "collision_index"), &PhysicsTestMotionResult3D::get_collider_rid, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider", "collision_index"), &PhysicsTestMotionResult3D::get_collider, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collider_shape", "collision_index"), &PhysicsTestMotionResult3D::get_collider_shape, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collision_local_shape", "collision_index"), &PhysicsTestMotionResult3D::get_collision_local_shape, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("get_collision_depth", "collision_index"), &PhysicsTestMotionResult3D::get_collision_depth, DEFVAL(0)); } /////////////////////////////////////// -bool PhysicsServer3D::_body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin, const Ref<PhysicsTestMotionResult3D> &p_result, bool p_collide_separation_ray, const Vector<RID> &p_exclude) { - MotionResult *r = nullptr; +bool PhysicsServer3D::_body_test_motion(RID p_body, const Ref<PhysicsTestMotionParameters3D> &p_parameters, const Ref<PhysicsTestMotionResult3D> &p_result) { + ERR_FAIL_COND_V(!p_parameters.is_valid(), false); + + MotionResult *result_ptr = nullptr; if (p_result.is_valid()) { - r = p_result->get_result_ptr(); - } - Set<RID> exclude; - for (int i = 0; i < p_exclude.size(); i++) { - exclude.insert(p_exclude[i]); + result_ptr = p_result->get_result_ptr(); } - return body_test_motion(p_body, p_from, p_motion, p_margin, r, p_collide_separation_ray, exclude); + + return body_test_motion(p_body, p_parameters->get_parameters(), result_ptr); } RID PhysicsServer3D::shape_create(ShapeType p_shape) { switch (p_shape) { - case SHAPE_PLANE: - return plane_shape_create(); + case SHAPE_WORLD_BOUNDARY: + return world_boundary_shape_create(); case SHAPE_SEPARATION_RAY: return separation_ray_shape_create(); case SHAPE_SPHERE: @@ -489,7 +634,7 @@ RID PhysicsServer3D::shape_create(ShapeType p_shape) { void PhysicsServer3D::_bind_methods() { #ifndef _3D_DISABLED - ClassDB::bind_method(D_METHOD("plane_shape_create"), &PhysicsServer3D::plane_shape_create); + ClassDB::bind_method(D_METHOD("world_boundary_shape_create"), &PhysicsServer3D::world_boundary_shape_create); ClassDB::bind_method(D_METHOD("separation_ray_shape_create"), &PhysicsServer3D::separation_ray_shape_create); ClassDB::bind_method(D_METHOD("sphere_shape_create"), &PhysicsServer3D::sphere_shape_create); ClassDB::bind_method(D_METHOD("box_shape_create"), &PhysicsServer3D::box_shape_create); @@ -516,9 +661,6 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("area_set_space", "area", "space"), &PhysicsServer3D::area_set_space); ClassDB::bind_method(D_METHOD("area_get_space", "area"), &PhysicsServer3D::area_get_space); - ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &PhysicsServer3D::area_set_space_override_mode); - ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &PhysicsServer3D::area_get_space_override_mode); - ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer3D::area_add_shape, DEFVAL(Transform3D()), DEFVAL(false)); ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &PhysicsServer3D::area_set_shape); ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &PhysicsServer3D::area_set_shape_transform); @@ -543,8 +685,8 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("area_attach_object_instance_id", "area", "id"), &PhysicsServer3D::area_attach_object_instance_id); ClassDB::bind_method(D_METHOD("area_get_object_instance_id", "area"), &PhysicsServer3D::area_get_object_instance_id); - ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "receiver", "method"), &PhysicsServer3D::area_set_monitor_callback); - ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "receiver", "method"), &PhysicsServer3D::area_set_area_monitor_callback); + ClassDB::bind_method(D_METHOD("area_set_monitor_callback", "area", "callback"), &PhysicsServer3D::area_set_monitor_callback); + ClassDB::bind_method(D_METHOD("area_set_area_monitor_callback", "area", "callback"), &PhysicsServer3D::area_set_area_monitor_callback); ClassDB::bind_method(D_METHOD("area_set_monitorable", "area", "monitorable"), &PhysicsServer3D::area_set_monitorable); ClassDB::bind_method(D_METHOD("area_set_ray_pickable", "area", "enable"), &PhysicsServer3D::area_set_ray_pickable); @@ -584,6 +726,8 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_param", "body", "param", "value"), &PhysicsServer3D::body_set_param); ClassDB::bind_method(D_METHOD("body_get_param", "body", "param"), &PhysicsServer3D::body_get_param); + ClassDB::bind_method(D_METHOD("body_reset_mass_properties", "body"), &PhysicsServer3D::body_reset_mass_properties); + ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer3D::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer3D::body_get_state); @@ -612,7 +756,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_ray_pickable", "body", "enable"), &PhysicsServer3D::body_set_ray_pickable); - ClassDB::bind_method(D_METHOD("body_test_motion", "body", "from", "motion", "margin", "result", "collide_separation_ray", "exclude"), &PhysicsServer3D::_body_test_motion, DEFVAL(0.001), DEFVAL(Variant()), DEFVAL(false), DEFVAL(Array())); + ClassDB::bind_method(D_METHOD("body_test_motion", "body", "parameters", "result"), &PhysicsServer3D::_body_test_motion, DEFVAL(Variant())); ClassDB::bind_method(D_METHOD("body_get_direct_state", "body"), &PhysicsServer3D::body_get_direct_state); @@ -750,7 +894,7 @@ void PhysicsServer3D::_bind_methods() { ClassDB::bind_method(D_METHOD("get_process_info", "process_info"), &PhysicsServer3D::get_process_info); - BIND_ENUM_CONSTANT(SHAPE_PLANE); + BIND_ENUM_CONSTANT(SHAPE_WORLD_BOUNDARY); BIND_ENUM_CONSTANT(SHAPE_SEPARATION_RAY); BIND_ENUM_CONSTANT(SHAPE_SPHERE); BIND_ENUM_CONSTANT(SHAPE_BOX); @@ -762,12 +906,15 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(SHAPE_SOFT_BODY); BIND_ENUM_CONSTANT(SHAPE_CUSTOM); + BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_OVERRIDE_MODE); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_VECTOR); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_IS_POINT); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_DISTANCE_SCALE); BIND_ENUM_CONSTANT(AREA_PARAM_GRAVITY_POINT_ATTENUATION); + BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE); BIND_ENUM_CONSTANT(AREA_PARAM_LINEAR_DAMP); + BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE); BIND_ENUM_CONSTANT(AREA_PARAM_ANGULAR_DAMP); BIND_ENUM_CONSTANT(AREA_PARAM_PRIORITY); BIND_ENUM_CONSTANT(AREA_PARAM_WIND_FORCE_MAGNITUDE); @@ -784,16 +931,23 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(BODY_MODE_STATIC); BIND_ENUM_CONSTANT(BODY_MODE_KINEMATIC); BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC); - BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LOCKED); + BIND_ENUM_CONSTANT(BODY_MODE_DYNAMIC_LINEAR); BIND_ENUM_CONSTANT(BODY_PARAM_BOUNCE); BIND_ENUM_CONSTANT(BODY_PARAM_FRICTION); BIND_ENUM_CONSTANT(BODY_PARAM_MASS); + BIND_ENUM_CONSTANT(BODY_PARAM_INERTIA); + BIND_ENUM_CONSTANT(BODY_PARAM_CENTER_OF_MASS); BIND_ENUM_CONSTANT(BODY_PARAM_GRAVITY_SCALE); + BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP_MODE); + BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP_MODE); BIND_ENUM_CONSTANT(BODY_PARAM_LINEAR_DAMP); BIND_ENUM_CONSTANT(BODY_PARAM_ANGULAR_DAMP); BIND_ENUM_CONSTANT(BODY_PARAM_MAX); + BIND_ENUM_CONSTANT(BODY_DAMP_MODE_COMBINE); + BIND_ENUM_CONSTANT(BODY_DAMP_MODE_REPLACE); + BIND_ENUM_CONSTANT(BODY_STATE_TRANSFORM); BIND_ENUM_CONSTANT(BODY_STATE_LINEAR_VELOCITY); BIND_ENUM_CONSTANT(BODY_STATE_ANGULAR_VELOCITY); @@ -815,7 +969,6 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_TIME_TO_SLEEP); BIND_ENUM_CONSTANT(SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO); BIND_ENUM_CONSTANT(SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS); - BIND_ENUM_CONSTANT(SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH); BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_X); BIND_ENUM_CONSTANT(BODY_AXIS_LINEAR_Y); diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index a365802220..89a7eeee96 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PHYSICS_SERVER_H -#define PHYSICS_SERVER_H +#ifndef PHYSICS_SERVER_3D_H +#define PHYSICS_SERVER_3D_H #include "core/io/resource.h" #include "core/object/class_db.h" @@ -48,6 +48,7 @@ public: virtual real_t get_total_linear_damp() const = 0; virtual Vector3 get_center_of_mass() const = 0; + virtual Vector3 get_center_of_mass_local() const = 0; virtual Basis get_principal_inertia_axes() const = 0; virtual real_t get_inverse_mass() const = 0; // get the mass virtual Vector3 get_inverse_inertia() const = 0; // get density of this body space @@ -96,57 +97,18 @@ public: PhysicsDirectBodyState3D(); }; -class PhysicsShapeQueryParameters3D : public RefCounted { - GDCLASS(PhysicsShapeQueryParameters3D, RefCounted); - friend class PhysicsDirectSpaceState3D; - - RES shape_ref; - RID shape; - Transform3D transform; - real_t margin; - Set<RID> exclude; - uint32_t collision_mask; - - bool collide_with_bodies; - bool collide_with_areas; - -protected: - static void _bind_methods(); - -public: - void set_shape(const RES &p_shape_ref); - RES get_shape() const; - void set_shape_rid(const RID &p_shape); - RID get_shape_rid() const; - - void set_transform(const Transform3D &p_transform); - Transform3D get_transform() const; - - void set_margin(real_t p_margin); - real_t get_margin() const; - - void set_collision_mask(uint32_t p_collision_mask); - uint32_t get_collision_mask() const; - - void set_exclude(const Vector<RID> &p_exclude); - Vector<RID> get_exclude() const; - - void set_collide_with_bodies(bool p_enable); - bool is_collide_with_bodies_enabled() const; - - void set_collide_with_areas(bool p_enable); - bool is_collide_with_areas_enabled() const; - - PhysicsShapeQueryParameters3D(); -}; +class PhysicsRayQueryParameters3D; +class PhysicsPointQueryParameters3D; +class PhysicsShapeQueryParameters3D; class PhysicsDirectSpaceState3D : public Object { GDCLASS(PhysicsDirectSpaceState3D, Object); private: - Dictionary _intersect_ray(const Vector3 &p_from, const Vector3 &p_to, const Vector<RID> &p_exclude = Vector<RID>(), uint32_t p_collision_mask = 0, bool p_collide_with_bodies = true, bool p_collide_with_areas = false); + Dictionary _intersect_ray(const Ref<PhysicsRayQueryParameters3D> &p_ray_query); + Array _intersect_point(const Ref<PhysicsPointQueryParameters3D> &p_point_query, int p_max_results = 32); Array _intersect_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32); - Array _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, const Vector3 &p_motion); + Array _cast_motion(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query); Array _collide_shape(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query, int p_max_results = 32); Dictionary _get_rest_info(const Ref<PhysicsShapeQueryParameters3D> &p_shape_query); @@ -154,27 +116,61 @@ protected: static void _bind_methods(); public: - struct ShapeResult { + struct RayParameters { + Vector3 from; + Vector3 to; + Set<RID> exclude; + uint32_t collision_mask = UINT32_MAX; + + bool collide_with_bodies = true; + bool collide_with_areas = false; + + bool hit_from_inside = false; + bool hit_back_faces = true; + + bool pick_ray = false; + }; + + struct RayResult { + Vector3 position; + Vector3 normal; RID rid; ObjectID collider_id; Object *collider = nullptr; int shape = 0; }; - virtual int intersect_point(const Vector3 &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) = 0; + virtual bool intersect_ray(const RayParameters &p_parameters, RayResult &r_result) = 0; - struct RayResult { - Vector3 position; - Vector3 normal; + struct ShapeResult { RID rid; ObjectID collider_id; Object *collider = nullptr; int shape = 0; }; - virtual bool intersect_ray(const Vector3 &p_from, const Vector3 &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, bool p_pick_ray = false) = 0; + struct PointParameters { + Vector3 position; + Set<RID> exclude; + uint32_t collision_mask = UINT32_MAX; + + bool collide_with_bodies = true; + bool collide_with_areas = false; + }; - virtual int intersect_shape(const RID &p_shape, const Transform3D &p_xform, 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) = 0; + virtual int intersect_point(const PointParameters &p_parameters, ShapeResult *r_results, int p_result_max) = 0; + + struct ShapeParameters { + RID shape_rid; + Transform3D transform; + Vector3 motion; + real_t margin = 0.0; + Set<RID> exclude; + uint32_t collision_mask = UINT32_MAX; + + bool collide_with_bodies = true; + bool collide_with_areas = false; + }; struct ShapeRestInfo { Vector3 point; @@ -182,14 +178,13 @@ public: RID rid; ObjectID collider_id; int shape = 0; - Vector3 linear_velocity; //velocity at contact point + Vector3 linear_velocity; // Velocity at contact point. }; - virtual bool cast_motion(const RID &p_shape, const Transform3D &p_xform, const Vector3 &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, ShapeRestInfo *r_info = nullptr) = 0; - - virtual bool collide_shape(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, Vector3 *r_results, int p_result_max, int &r_result_count, 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) = 0; - - virtual bool rest_info(RID p_shape, const Transform3D &p_shape_xform, real_t p_margin, ShapeRestInfo *r_info, 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) = 0; + virtual int intersect_shape(const ShapeParameters &p_parameters, ShapeResult *r_results, int p_result_max) = 0; + virtual bool cast_motion(const ShapeParameters &p_parameters, real_t &p_closest_safe, real_t &p_closest_unsafe, ShapeRestInfo *r_info = nullptr) = 0; + virtual bool collide_shape(const ShapeParameters &p_parameters, Vector3 *r_results, int p_result_max, int &r_result_count) = 0; + virtual bool rest_info(const ShapeParameters &p_parameters, ShapeRestInfo *r_info) = 0; virtual Vector3 get_closest_point_to_object_volume(RID p_object, const Vector3 p_point) const = 0; @@ -205,6 +200,7 @@ public: virtual ~RenderingServerHandler() {} }; +class PhysicsTestMotionParameters3D; class PhysicsTestMotionResult3D; class PhysicsServer3D : public Object { @@ -212,7 +208,7 @@ class PhysicsServer3D : public Object { static PhysicsServer3D *singleton; - virtual bool _body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>(), bool p_collide_separation_ray = false, const Vector<RID> &p_exclude = Vector<RID>()); + virtual bool _body_test_motion(RID p_body, const Ref<PhysicsTestMotionParameters3D> &p_parameters, const Ref<PhysicsTestMotionResult3D> &p_result = Ref<PhysicsTestMotionResult3D>()); protected: static void _bind_methods(); @@ -221,7 +217,7 @@ public: static PhysicsServer3D *get_singleton(); enum ShapeType { - SHAPE_PLANE, ///< plane:"plane" + SHAPE_WORLD_BOUNDARY, ///< plane:"plane" SHAPE_SEPARATION_RAY, ///< float:"length" SHAPE_SPHERE, ///< float:"radius" SHAPE_BOX, ///< vec3:"extents" @@ -236,7 +232,7 @@ public: RID shape_create(ShapeType p_shape); - virtual RID plane_shape_create() = 0; + virtual RID world_boundary_shape_create() = 0; virtual RID separation_ray_shape_create() = 0; virtual RID sphere_shape_create() = 0; virtual RID box_shape_create() = 0; @@ -273,7 +269,6 @@ public: SPACE_PARAM_BODY_TIME_TO_SLEEP, SPACE_PARAM_BODY_ANGULAR_VELOCITY_DAMP_RATIO, SPACE_PARAM_CONSTRAINT_DEFAULT_BIAS, - SPACE_PARAM_TEST_MOTION_MIN_CONTACT_DEPTH }; virtual void space_set_param(RID p_space, SpaceParameter p_param, real_t p_value) = 0; @@ -293,12 +288,15 @@ public: //missing attenuation? missing better override? enum AreaParameter { + AREA_PARAM_GRAVITY_OVERRIDE_MODE, AREA_PARAM_GRAVITY, AREA_PARAM_GRAVITY_VECTOR, AREA_PARAM_GRAVITY_IS_POINT, AREA_PARAM_GRAVITY_DISTANCE_SCALE, AREA_PARAM_GRAVITY_POINT_ATTENUATION, + AREA_PARAM_LINEAR_DAMP_OVERRIDE_MODE, AREA_PARAM_LINEAR_DAMP, + AREA_PARAM_ANGULAR_DAMP_OVERRIDE_MODE, AREA_PARAM_ANGULAR_DAMP, AREA_PARAM_PRIORITY, AREA_PARAM_WIND_FORCE_MAGNITUDE, @@ -320,9 +318,6 @@ public: AREA_SPACE_OVERRIDE_REPLACE_COMBINE }; - virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0; - virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0; - virtual void area_add_shape(RID p_area, RID p_shape, const Transform3D &p_transform = Transform3D(), bool p_disabled = false) = 0; virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0; virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform3D &p_transform) = 0; @@ -350,8 +345,8 @@ public: virtual void area_set_monitorable(RID p_area, bool p_monitorable) = 0; - virtual void area_set_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0; - virtual void area_set_area_monitor_callback(RID p_area, Object *p_receiver, const StringName &p_method) = 0; + virtual void area_set_monitor_callback(RID p_area, const Callable &p_callback) = 0; + virtual void area_set_area_monitor_callback(RID p_area, const Callable &p_callback) = 0; virtual void area_set_ray_pickable(RID p_area, bool p_enable) = 0; @@ -363,7 +358,12 @@ public: BODY_MODE_STATIC, BODY_MODE_KINEMATIC, BODY_MODE_DYNAMIC, - BODY_MODE_DYNAMIC_LOCKED, + BODY_MODE_DYNAMIC_LINEAR, + }; + + enum BodyDampMode { + BODY_DAMP_MODE_COMBINE, + BODY_DAMP_MODE_REPLACE, }; virtual RID body_create() = 0; @@ -407,14 +407,20 @@ public: BODY_PARAM_BOUNCE, BODY_PARAM_FRICTION, BODY_PARAM_MASS, ///< unused for static, always infinite + BODY_PARAM_INERTIA, + BODY_PARAM_CENTER_OF_MASS, BODY_PARAM_GRAVITY_SCALE, + BODY_PARAM_LINEAR_DAMP_MODE, + BODY_PARAM_ANGULAR_DAMP_MODE, BODY_PARAM_LINEAR_DAMP, BODY_PARAM_ANGULAR_DAMP, BODY_PARAM_MAX, }; - virtual void body_set_param(RID p_body, BodyParameter p_param, real_t p_value) = 0; - virtual real_t body_get_param(RID p_body, BodyParameter p_param) const = 0; + virtual void body_set_param(RID p_body, BodyParameter p_param, const Variant &p_value) = 0; + virtual Variant body_get_param(RID p_body, BodyParameter p_param) const = 0; + + virtual void body_reset_mass_properties(RID p_body) = 0; //state enum BodyState { @@ -482,28 +488,50 @@ public: // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState3D *body_get_direct_state(RID p_body) = 0; - struct MotionResult { - Vector3 travel; - Vector3 remainder; + struct MotionParameters { + Transform3D from; + Vector3 motion; + real_t margin = 0.001; + int max_collisions = 1; + bool collide_separation_ray = false; + Set<RID> exclude_bodies; + Set<ObjectID> exclude_objects; + + MotionParameters() {} + + MotionParameters(const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001) : + from(p_from), + motion(p_motion), + margin(p_margin) {} + }; - Vector3 collision_point; - Vector3 collision_normal; + struct MotionCollision { + Vector3 position; + Vector3 normal; Vector3 collider_velocity; - real_t collision_depth = 0.0; - real_t collision_safe_fraction = 0.0; - real_t collision_unsafe_fraction = 0.0; - int collision_local_shape = 0; + real_t depth = 0.0; + int local_shape = 0; ObjectID collider_id; RID collider; int collider_shape = 0; - Variant collider_metadata; real_t get_angle(Vector3 p_up_direction) const { - return Math::acos(collision_normal.dot(p_up_direction)); + return Math::acos(normal.dot(p_up_direction)); } }; - virtual bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) = 0; + struct MotionResult { + Vector3 travel; + Vector3 remainder; + real_t collision_safe_fraction = 0.0; + real_t collision_unsafe_fraction = 0.0; + + static const int MAX_COLLISIONS = 32; + MotionCollision collisions[MAX_COLLISIONS]; + int collision_count = 0; + }; + + virtual bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) = 0; /* SOFT BODY */ @@ -514,7 +542,7 @@ public: virtual void soft_body_set_space(RID p_body, RID p_space) = 0; virtual RID soft_body_get_space(RID p_body) const = 0; - virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) = 0; + virtual void soft_body_set_mesh(RID p_body, RID p_mesh) = 0; virtual AABB soft_body_get_bounds(RID p_body) const = 0; @@ -754,11 +782,147 @@ public: ~PhysicsServer3D(); }; +class PhysicsRayQueryParameters3D : public RefCounted { + GDCLASS(PhysicsRayQueryParameters3D, RefCounted); + + PhysicsDirectSpaceState3D::RayParameters parameters; + +protected: + static void _bind_methods(); + +public: + const PhysicsDirectSpaceState3D::RayParameters &get_parameters() const { return parameters; } + + void set_from(const Vector3 &p_from) { parameters.from = p_from; } + const Vector3 &get_from() const { return parameters.from; } + + void set_to(const Vector3 &p_to) { parameters.to = p_to; } + const Vector3 &get_to() const { return parameters.to; } + + void set_collision_mask(uint32_t p_mask) { parameters.collision_mask = p_mask; } + uint32_t get_collision_mask() const { return parameters.collision_mask; } + + void set_collide_with_bodies(bool p_enable) { parameters.collide_with_bodies = p_enable; } + bool is_collide_with_bodies_enabled() const { return parameters.collide_with_bodies; } + + void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; } + bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; } + + void set_hit_from_inside(bool p_enable) { parameters.hit_from_inside = p_enable; } + bool is_hit_from_inside_enabled() const { return parameters.hit_from_inside; } + + void set_hit_back_faces(bool p_enable) { parameters.hit_back_faces = p_enable; } + bool is_hit_back_faces_enabled() const { return parameters.hit_back_faces; } + + void set_exclude(const Vector<RID> &p_exclude); + Vector<RID> get_exclude() const; +}; + +class PhysicsPointQueryParameters3D : public RefCounted { + GDCLASS(PhysicsPointQueryParameters3D, RefCounted); + + PhysicsDirectSpaceState3D::PointParameters parameters; + +protected: + static void _bind_methods(); + +public: + const PhysicsDirectSpaceState3D::PointParameters &get_parameters() const { return parameters; } + + void set_position(const Vector3 &p_position) { parameters.position = p_position; } + const Vector3 &get_position() const { return parameters.position; } + + void set_collision_mask(uint32_t p_mask) { parameters.collision_mask = p_mask; } + uint32_t get_collision_mask() const { return parameters.collision_mask; } + + void set_collide_with_bodies(bool p_enable) { parameters.collide_with_bodies = p_enable; } + bool is_collide_with_bodies_enabled() const { return parameters.collide_with_bodies; } + + void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; } + bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; } + + void set_exclude(const Vector<RID> &p_exclude); + Vector<RID> get_exclude() const; +}; + +class PhysicsShapeQueryParameters3D : public RefCounted { + GDCLASS(PhysicsShapeQueryParameters3D, RefCounted); + + PhysicsDirectSpaceState3D::ShapeParameters parameters; + + RES shape_ref; + +protected: + static void _bind_methods(); + +public: + const PhysicsDirectSpaceState3D::ShapeParameters &get_parameters() const { return parameters; } + + void set_shape(const RES &p_shape_ref); + RES get_shape() const { return shape_ref; } + + void set_shape_rid(const RID &p_shape); + RID get_shape_rid() const { return parameters.shape_rid; } + + void set_transform(const Transform3D &p_transform) { parameters.transform = p_transform; } + const Transform3D &get_transform() const { return parameters.transform; } + + void set_motion(const Vector3 &p_motion) { parameters.motion = p_motion; } + const Vector3 &get_motion() const { return parameters.motion; } + + void set_margin(real_t p_margin) { parameters.margin = p_margin; } + real_t get_margin() const { return parameters.margin; } + + void set_collision_mask(uint32_t p_mask) { parameters.collision_mask = p_mask; } + uint32_t get_collision_mask() const { return parameters.collision_mask; } + + void set_collide_with_bodies(bool p_enable) { parameters.collide_with_bodies = p_enable; } + bool is_collide_with_bodies_enabled() const { return parameters.collide_with_bodies; } + + void set_collide_with_areas(bool p_enable) { parameters.collide_with_areas = p_enable; } + bool is_collide_with_areas_enabled() const { return parameters.collide_with_areas; } + + void set_exclude(const Vector<RID> &p_exclude); + Vector<RID> get_exclude() const; +}; + +class PhysicsTestMotionParameters3D : public RefCounted { + GDCLASS(PhysicsTestMotionParameters3D, RefCounted); + + PhysicsServer3D::MotionParameters parameters; + +protected: + static void _bind_methods(); + +public: + const PhysicsServer3D::MotionParameters &get_parameters() const { return parameters; } + + const Transform3D &get_from() const { return parameters.from; } + void set_from(const Transform3D &p_from) { parameters.from = p_from; } + + const Vector3 &get_motion() const { return parameters.motion; } + void set_motion(const Vector3 &p_motion) { parameters.motion = p_motion; } + + real_t get_margin() const { return parameters.margin; } + void set_margin(real_t p_margin) { parameters.margin = p_margin; } + + int get_max_collisions() const { return parameters.max_collisions; } + void set_max_collisions(int p_max_collisions) { parameters.max_collisions = p_max_collisions; } + + bool is_collide_separation_ray_enabled() const { return parameters.collide_separation_ray; } + void set_collide_separation_ray_enabled(bool p_enabled) { parameters.collide_separation_ray = p_enabled; } + + Vector<RID> get_exclude_bodies() const; + void set_exclude_bodies(const Vector<RID> &p_exclude); + + Array get_exclude_objects() const; + void set_exclude_objects(const Array &p_exclude); +}; + class PhysicsTestMotionResult3D : public RefCounted { GDCLASS(PhysicsTestMotionResult3D, RefCounted); PhysicsServer3D::MotionResult result; - friend class PhysicsServer3D; protected: static void _bind_methods(); @@ -768,17 +932,20 @@ public: Vector3 get_travel() const; Vector3 get_remainder() const; - - Vector3 get_collision_point() const; - Vector3 get_collision_normal() const; - Vector3 get_collider_velocity() const; - ObjectID get_collider_id() const; - RID get_collider_rid() const; - Object *get_collider() const; - int get_collider_shape() const; - real_t get_collision_depth() const; real_t get_collision_safe_fraction() const; real_t get_collision_unsafe_fraction() const; + + int get_collision_count() const; + + Vector3 get_collision_point(int p_collision_index = 0) const; + Vector3 get_collision_normal(int p_collision_index = 0) const; + Vector3 get_collider_velocity(int p_collision_index = 0) const; + ObjectID get_collider_id(int p_collision_index = 0) const; + RID get_collider_rid(int p_collision_index = 0) const; + Object *get_collider(int p_collision_index = 0) const; + int get_collider_shape(int p_collision_index = 0) const; + int get_collision_local_shape(int p_collision_index = 0) const; + real_t get_collision_depth(int p_collision_index = 0) const; }; typedef PhysicsServer3D *(*CreatePhysicsServer3DCallback)(); @@ -831,6 +998,7 @@ VARIANT_ENUM_CAST(PhysicsServer3D::AreaParameter); VARIANT_ENUM_CAST(PhysicsServer3D::AreaSpaceOverrideMode); VARIANT_ENUM_CAST(PhysicsServer3D::BodyMode); VARIANT_ENUM_CAST(PhysicsServer3D::BodyParameter); +VARIANT_ENUM_CAST(PhysicsServer3D::BodyDampMode); VARIANT_ENUM_CAST(PhysicsServer3D::BodyState); VARIANT_ENUM_CAST(PhysicsServer3D::BodyAxis); VARIANT_ENUM_CAST(PhysicsServer3D::PinJointParam); @@ -844,4 +1012,4 @@ VARIANT_ENUM_CAST(PhysicsServer3D::G6DOFJointAxisFlag); VARIANT_ENUM_CAST(PhysicsServer3D::AreaBodyStatus); VARIANT_ENUM_CAST(PhysicsServer3D::ProcessInfo); -#endif +#endif // PHYSICS_SERVER_3D_H diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.cpp b/servers/physics_server_3d_wrap_mt.cpp index 0a89c1a9c9..c424100bba 100644 --- a/servers/physics_3d/physics_server_3d_wrap_mt.cpp +++ b/servers/physics_server_3d_wrap_mt.cpp @@ -119,8 +119,6 @@ PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool command_queue(p_create_thread) { physics_3d_server = p_contained; create_thread = p_create_thread; - step_pending = 0; - step_thread_up = false; pool_max_size = GLOBAL_GET("memory/limits/multithreaded_server/rid_pool_prealloc"); @@ -131,7 +129,6 @@ PhysicsServer3DWrapMT::PhysicsServer3DWrapMT(PhysicsServer3D *p_contained, bool } main_thread = Thread::get_caller_id(); - first_frame = true; } PhysicsServer3DWrapMT::~PhysicsServer3DWrapMT() { diff --git a/servers/physics_3d/physics_server_3d_wrap_mt.h b/servers/physics_server_3d_wrap_mt.h index 8865bd4bd2..507427ecec 100644 --- a/servers/physics_3d/physics_server_3d_wrap_mt.h +++ b/servers/physics_server_3d_wrap_mt.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef PHYSICS3DSERVERWRAPMT_H -#define PHYSICS3DSERVERWRAPMT_H +#ifndef PHYSICS_SERVER_3D_WRAP_MT_H +#define PHYSICS_SERVER_3D_WRAP_MT_H #include "core/config/project_settings.h" #include "core/os/thread.h" @@ -58,9 +58,7 @@ class PhysicsServer3DWrapMT : public PhysicsServer3D { bool create_thread = false; Semaphore step_sem; - int step_pending; void thread_step(real_t p_delta); - void thread_flush(); void thread_exit(); @@ -78,7 +76,7 @@ public: #include "servers/server_wrap_mt_common.h" //FUNC1RID(shape,ShapeType); todo fix - FUNCRID(plane_shape) + FUNCRID(world_boundary_shape) FUNCRID(separation_ray_shape) FUNCRID(sphere_shape) FUNCRID(box_shape) @@ -139,9 +137,6 @@ public: FUNC2(area_set_space, RID, RID); FUNC1RC(RID, area_get_space, RID); - FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode); - FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID); - FUNC4(area_add_shape, RID, RID, const Transform3D &, bool); FUNC3(area_set_shape, RID, int, RID); FUNC3(area_set_shape_transform, RID, int, const Transform3D &); @@ -168,8 +163,8 @@ public: FUNC2(area_set_monitorable, RID, bool); FUNC2(area_set_ray_pickable, RID, bool); - FUNC3(area_set_monitor_callback, RID, Object *, const StringName &); - FUNC3(area_set_area_monitor_callback, RID, Object *, const StringName &); + FUNC2(area_set_monitor_callback, RID, const Callable &); + FUNC2(area_set_area_monitor_callback, RID, const Callable &); /* BODY API */ @@ -210,8 +205,10 @@ public: FUNC2(body_set_user_flags, RID, uint32_t); FUNC1RC(uint32_t, body_get_user_flags, RID); - FUNC3(body_set_param, RID, BodyParameter, real_t); - FUNC2RC(real_t, body_get_param, RID, BodyParameter); + FUNC3(body_set_param, RID, BodyParameter, const Variant &); + FUNC2RC(Variant, body_get_param, RID, BodyParameter); + + FUNC1(body_reset_mass_properties, RID); FUNC3(body_set_state, RID, BodyState, const Variant &); FUNC2RC(Variant, body_get_state, RID, BodyState); @@ -251,9 +248,9 @@ public: FUNC2(body_set_ray_pickable, RID, bool); - bool body_test_motion(RID p_body, const Transform3D &p_from, const Vector3 &p_motion, real_t p_margin = 0.001, MotionResult *r_result = nullptr, bool p_collide_separation_ray = false, const Set<RID> &p_exclude = Set<RID>()) override { + bool body_test_motion(RID p_body, const MotionParameters &p_parameters, MotionResult *r_result = nullptr) override { ERR_FAIL_COND_V(main_thread != Thread::get_caller_id(), false); - return physics_3d_server->body_test_motion(p_body, p_from, p_motion, p_margin, r_result, p_collide_separation_ray, p_exclude); + return physics_3d_server->body_test_motion(p_body, p_parameters, r_result); } // this function only works on physics process, errors and returns null otherwise @@ -306,7 +303,7 @@ public: FUNC2(soft_body_set_drag_coefficient, RID, real_t); FUNC1RC(real_t, soft_body_get_drag_coefficient, RID); - FUNC2(soft_body_set_mesh, RID, const REF &); + FUNC2(soft_body_set_mesh, RID, RID); FUNC1RC(AABB, soft_body_get_bounds, RID); @@ -404,4 +401,4 @@ public: #endif #undef SYNC_DEBUG -#endif // PHYSICS3DSERVERWRAPMT_H +#endif // PHYSICS_SERVER_3D_WRAP_MT_H diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 41c8b45113..7004b2317c 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -59,17 +59,18 @@ #include "display_server.h" #include "navigation_server_2d.h" #include "navigation_server_3d.h" -#include "physics_2d/physics_server_2d_sw.h" -#include "physics_2d/physics_server_2d_wrap_mt.h" -#include "physics_3d/physics_server_3d_sw.h" -#include "physics_3d/physics_server_3d_wrap_mt.h" +#include "physics_2d/godot_physics_server_2d.h" +#include "physics_3d/godot_physics_server_3d.h" #include "physics_server_2d.h" +#include "physics_server_2d_wrap_mt.h" #include "physics_server_3d.h" +#include "physics_server_3d_wrap_mt.h" #include "rendering/renderer_compositor.h" #include "rendering/rendering_device.h" #include "rendering/rendering_device_binds.h" #include "rendering_server.h" #include "servers/rendering/shader_types.h" +#include "text/text_server_extension.h" #include "text_server.h" #include "xr/xr_interface.h" #include "xr/xr_interface_extension.h" @@ -81,7 +82,7 @@ ShaderTypes *shader_types = nullptr; PhysicsServer3D *_createGodotPhysics3DCallback() { bool using_threads = GLOBAL_GET("physics/3d/run_on_thread"); - PhysicsServer3D *physics_server = memnew(PhysicsServer3DSW(using_threads)); + PhysicsServer3D *physics_server = memnew(GodotPhysicsServer3D(using_threads)); return memnew(PhysicsServer3DWrapMT(physics_server, using_threads)); } @@ -89,7 +90,7 @@ PhysicsServer3D *_createGodotPhysics3DCallback() { PhysicsServer2D *_createGodotPhysics2DCallback() { bool using_threads = GLOBAL_GET("physics/2d/run_on_thread"); - PhysicsServer2D *physics_server = memnew(PhysicsServer2DSW(using_threads)); + PhysicsServer2D *physics_server = memnew(GodotPhysicsServer2D(using_threads)); return memnew(PhysicsServer2DWrapMT(physics_server, using_threads)); } @@ -107,15 +108,11 @@ static bool has_server_feature_callback(const String &p_feature) { void preregister_server_types() { shader_types = memnew(ShaderTypes); - GLOBAL_DEF("internationalization/rendering/text_driver", ""); - String text_driver_options; - for (int i = 0; i < TextServerManager::get_interface_count(); i++) { - if (i > 0) { - text_driver_options += ","; - } - text_driver_options += TextServerManager::get_interface_name(i); - } - ProjectSettings::get_singleton()->set_custom_property_info("internationalization/rendering/text_driver", PropertyInfo(Variant::STRING, "internationalization/rendering/text_driver", PROPERTY_HINT_ENUM, text_driver_options)); + GDREGISTER_CLASS(TextServerManager); + GDREGISTER_VIRTUAL_CLASS(TextServer); + GDREGISTER_CLASS(TextServerExtension); + + Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton(), "TextServerManager")); } void register_server_types() { @@ -125,10 +122,6 @@ void register_server_types() { GDREGISTER_VIRTUAL_CLASS(RenderingServer); GDREGISTER_CLASS(AudioServer); - GDREGISTER_CLASS(TextServerManager); - GDREGISTER_VIRTUAL_CLASS(TextServer); - TextServer::initialize_hex_code_box_fonts(); - GDREGISTER_VIRTUAL_CLASS(PhysicsServer2D); GDREGISTER_VIRTUAL_CLASS(PhysicsServer3D); GDREGISTER_VIRTUAL_CLASS(NavigationServer2D); @@ -140,6 +133,7 @@ void register_server_types() { GDREGISTER_VIRTUAL_CLASS(XRInterface); GDREGISTER_CLASS(XRInterfaceExtension); // can't register this as virtual because we need a creation function for our extensions. + GDREGISTER_CLASS(XRPose); GDREGISTER_CLASS(XRPositionalTracker); GDREGISTER_CLASS(AudioStream); @@ -215,12 +209,18 @@ void register_server_types() { GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState2D); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState2D); - GDREGISTER_CLASS(PhysicsTestMotionResult2D); + GDREGISTER_CLASS(PhysicsRayQueryParameters2D); + GDREGISTER_CLASS(PhysicsPointQueryParameters2D); GDREGISTER_CLASS(PhysicsShapeQueryParameters2D); + GDREGISTER_CLASS(PhysicsTestMotionParameters2D); + GDREGISTER_CLASS(PhysicsTestMotionResult2D); - GDREGISTER_CLASS(PhysicsShapeQueryParameters3D); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectBodyState3D); GDREGISTER_VIRTUAL_CLASS(PhysicsDirectSpaceState3D); + GDREGISTER_CLASS(PhysicsRayQueryParameters3D); + GDREGISTER_CLASS(PhysicsPointQueryParameters3D); + GDREGISTER_CLASS(PhysicsShapeQueryParameters3D); + GDREGISTER_CLASS(PhysicsTestMotionParameters3D); GDREGISTER_CLASS(PhysicsTestMotionResult3D); // Physics 2D @@ -244,7 +244,6 @@ void unregister_server_types() { NativeExtensionManager::get_singleton()->deinitialize_extensions(NativeExtension::INITIALIZATION_LEVEL_SERVERS); memdelete(shader_types); - TextServer::finish_hex_code_box_fonts(); } void register_server_singletons() { @@ -255,7 +254,6 @@ void register_server_singletons() { Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton(), "PhysicsServer3D")); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton_mut(), "NavigationServer2D")); Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton_mut(), "NavigationServer3D")); - Engine::get_singleton()->add_singleton(Engine::Singleton("TextServerManager", TextServerManager::get_singleton(), "TextServerManager")); Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton(), "XRServer")); Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer")); } diff --git a/servers/rendering/rasterizer_dummy.h b/servers/rendering/rasterizer_dummy.h index f58d124140..3451ea2d39 100644 --- a/servers/rendering/rasterizer_dummy.h +++ b/servers/rendering/rasterizer_dummy.h @@ -55,6 +55,9 @@ public: void geometry_instance_set_lightmap_capture(GeometryInstance *p_geometry_instance, const Color *p_sh9) override {} void geometry_instance_set_instance_shader_parameters_offset(GeometryInstance *p_geometry_instance, int32_t p_offset) override {} void geometry_instance_set_cast_double_sided_shadows(GeometryInstance *p_geometry_instance, bool p_enable) override {} + void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override {} + void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) override {} + void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) override {} uint32_t geometry_instance_get_pair_mask() override { return 0; } void geometry_instance_pair_light_instances(GeometryInstance *p_geometry_instance, const RID *p_light_instances, uint32_t p_light_instance_count) override {} @@ -103,7 +106,7 @@ public: void environment_set_bg_color(RID p_env, const Color &p_color) override {} void environment_set_bg_energy(RID p_env, float p_energy) override {} void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override {} - void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) override {} + void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) override {} void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) override {} void environment_glow_set_use_bicubic_upscale(bool p_enable) override {} @@ -125,7 +128,7 @@ public: void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) override {} void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) override {} - void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) override {} + void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) override {} void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override {} void environment_set_volumetric_fog_filter_active(bool p_enable) override {} @@ -152,6 +155,12 @@ public: void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale = 1.0, float p_range_begin = 0, const Vector2 &p_uv_scale = Vector2()) override {} void light_instance_mark_visible(RID p_light_instance) override {} + RID fog_volume_instance_create(RID p_fog_volume) override { return RID(); } + void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override {} + void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override {} + RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override { return RID(); } + Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override { return Vector3(); } + RID reflection_atlas_create() override { return RID(); } int reflection_atlas_get_size(RID p_ref_atlas) const override { return 0; } void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override {} @@ -177,7 +186,7 @@ public: void voxel_gi_set_quality(RS::VoxelGIQuality) override {} - void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {} + void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_info = nullptr) override {} void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override {} void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) override {} @@ -186,7 +195,7 @@ public: void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) override {} RID render_buffers_create() override { return RID(); } - void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {} + void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override {} void gi_set_use_half_resolution(bool p_enable) override {} void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_curve) override {} @@ -197,7 +206,7 @@ public: TypedArray<Image> bake_render_uv2(RID p_base, const Vector<RID> &p_material_overrides, const Size2i &p_image_size) override { return TypedArray<Image>(); } - bool free(RID p_rid) override { return true; } + bool free(RID p_rid) override { return false; } void update() override {} void sdfgi_set_debug_probe_select(const Vector3 &p_position, const Vector3 &p_dir) override {} @@ -224,7 +233,7 @@ public: return texture_owner.make_rid(texture); } void texture_2d_initialize(RID p_texture, const Ref<Image> &p_image) override { - DummyTexture *t = texture_owner.getornull(p_texture); + DummyTexture *t = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!t); t->image = p_image->duplicate(); } @@ -241,7 +250,7 @@ public: void texture_3d_placeholder_initialize(RID p_texture) override {} Ref<Image> texture_2d_get(RID p_texture) const override { - DummyTexture *t = texture_owner.getornull(p_texture); + DummyTexture *t = texture_owner.get_or_null(p_texture); ERR_FAIL_COND_V(!t, Ref<Image>()); return t->image; } @@ -249,7 +258,7 @@ public: Ref<Image> texture_2d_layer_get(RID p_texture, int p_layer) const override { return Ref<Image>(); } Vector<Ref<Image>> texture_3d_get(RID p_texture) const override { return Vector<Ref<Image>>(); } - void texture_replace(RID p_texture, RID p_by_texture) override {} + void texture_replace(RID p_texture, RID p_by_texture) override { free(p_by_texture); } void texture_set_size_override(RID p_texture, int p_width, int p_height) override {} void texture_set_path(RID p_texture, const String &p_path) override {} @@ -284,8 +293,8 @@ public: String shader_get_code(RID p_shader) const override { return ""; } void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const override {} - void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) override {} - RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const override { return RID(); } + void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) override {} + RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const override { return RID(); } Variant shader_get_param_default(RID p_material, const StringName &p_param) const override { return Variant(); } RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const override { return RS::ShaderNativeSourceCode(); }; @@ -607,6 +616,17 @@ public: void particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) override {} void particles_collision_instance_set_active(RID p_collision_instance, bool p_active) override {} + /* FOG VOLUMES */ + + RID fog_volume_allocate() override { return RID(); } + void fog_volume_initialize(RID p_rid) override {} + + void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) override {} + void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) override {} + void fog_volume_set_material(RID p_fog_volume, RID p_material) override {} + AABB fog_volume_get_aabb(RID p_fog_volume) const override { return AABB(); } + RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const override { return RS::FOG_VOLUME_SHAPE_BOX; } + /* VISIBILITY NOTIFIER */ virtual RID visibility_notifier_allocate() override { return RID(); } virtual void visibility_notifier_initialize(RID p_notifier) override {} @@ -661,11 +681,12 @@ public: bool free(RID p_rid) override { if (texture_owner.owns(p_rid)) { // delete the texture - DummyTexture *texture = texture_owner.getornull(p_rid); + DummyTexture *texture = texture_owner.get_or_null(p_rid); texture_owner.free(p_rid); memdelete(texture); + return true; } - return true; + return false; } virtual void update_memory_info() override {} diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index efa3a457d3..7b70483571 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -100,7 +100,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2 void _mark_ysort_dirty(RendererCanvasCull::Item *ysort_owner, RID_Owner<RendererCanvasCull::Item, true> &canvas_item_owner) { do { ysort_owner->ysort_children_count = -1; - ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.getornull(ysort_owner->parent) : nullptr; + ysort_owner = canvas_item_owner.owns(ysort_owner->parent) ? canvas_item_owner.get_or_null(ysort_owner->parent) : nullptr; } while (ysort_owner && ysort_owner->sort_y); } @@ -137,8 +137,7 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item * // We have two choices now, if user has drawn something, we must assume users wants to draw the "mask", so compute the size based on this. // If nothing has been drawn, we just take it over and draw it ourselves. - if (ci->canvas_group->fit_empty && (ci->commands == nullptr || - (ci->commands->next == nullptr && ci->commands->type == RendererCanvasCull::Item::Command::TYPE_RECT && (static_cast<RendererCanvasCull::Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) { + if (ci->canvas_group->fit_empty && (ci->commands == nullptr || (ci->commands->next == nullptr && ci->commands->type == RendererCanvasCull::Item::Command::TYPE_RECT && (static_cast<RendererCanvasCull::Item::CommandRect *>(ci->commands)->flags & RendererCanvasRender::CANVAS_RECT_IS_GROUP)))) { // No commands, or sole command is the one used to draw, so we (re)create the draw command. ci->clear(); @@ -182,7 +181,7 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item * if (ci->commands != nullptr) { ci->final_transform = xform; - ci->final_modulate = Color(modulate.r * ci->self_modulate.r, modulate.g * ci->self_modulate.g, modulate.b * ci->self_modulate.b, modulate.a * ci->self_modulate.a); + ci->final_modulate = modulate * ci->self_modulate; ci->global_rect_cache = global_rect; ci->global_rect_cache.position -= p_clip_rect.position; ci->light_masked = false; @@ -396,9 +395,9 @@ void RendererCanvasCull::canvas_initialize(RID p_rid) { } void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) { - Canvas *canvas = canvas_owner.getornull(p_canvas); + Canvas *canvas = canvas_owner.get_or_null(p_canvas); ERR_FAIL_COND(!canvas); - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); int idx = canvas->find_item(canvas_item); @@ -407,7 +406,7 @@ void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, con } void RendererCanvasCull::canvas_set_modulate(RID p_canvas, const Color &p_color) { - Canvas *canvas = canvas_owner.getornull(p_canvas); + Canvas *canvas = canvas_owner.get_or_null(p_canvas); ERR_FAIL_COND(!canvas); canvas->modulate = p_color; } @@ -417,7 +416,7 @@ void RendererCanvasCull::canvas_set_disable_scale(bool p_disable) { } void RendererCanvasCull::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) { - Canvas *canvas = canvas_owner.getornull(p_canvas); + Canvas *canvas = canvas_owner.get_or_null(p_canvas); ERR_FAIL_COND(!canvas); canvas->parent = p_parent; @@ -432,15 +431,15 @@ void RendererCanvasCull::canvas_item_initialize(RID p_rid) { } void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); if (canvas_item->parent.is_valid()) { if (canvas_owner.owns(canvas_item->parent)) { - Canvas *canvas = canvas_owner.getornull(canvas_item->parent); + Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent); canvas->erase_item(canvas_item); } else if (canvas_item_owner.owns(canvas_item->parent)) { - Item *item_owner = canvas_item_owner.getornull(canvas_item->parent); + Item *item_owner = canvas_item_owner.get_or_null(canvas_item->parent); item_owner->child_items.erase(canvas_item); if (item_owner->sort_y) { @@ -453,13 +452,13 @@ void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) { if (p_parent.is_valid()) { if (canvas_owner.owns(p_parent)) { - Canvas *canvas = canvas_owner.getornull(p_parent); + Canvas *canvas = canvas_owner.get_or_null(p_parent); Canvas::ChildItem ci; ci.item = canvas_item; canvas->child_items.push_back(ci); canvas->children_order_dirty = true; } else if (canvas_item_owner.owns(p_parent)) { - Item *item_owner = canvas_item_owner.getornull(p_parent); + Item *item_owner = canvas_item_owner.get_or_null(p_parent); item_owner->child_items.push_back(canvas_item); item_owner->children_order_dirty = true; @@ -476,7 +475,7 @@ void RendererCanvasCull::canvas_item_set_parent(RID p_item, RID p_parent) { } void RendererCanvasCull::canvas_item_set_visible(RID p_item, bool p_visible) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->visible = p_visible; @@ -485,35 +484,35 @@ void RendererCanvasCull::canvas_item_set_visible(RID p_item, bool p_visible) { } void RendererCanvasCull::canvas_item_set_light_mask(RID p_item, int p_mask) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->light_mask = p_mask; } void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D &p_transform) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->xform = p_transform; } void RendererCanvasCull::canvas_item_set_clip(RID p_item, bool p_clip) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->clip = p_clip; } void RendererCanvasCull::canvas_item_set_distance_field_mode(RID p_item, bool p_enable) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->distance_field = p_enable; } void RendererCanvasCull::canvas_item_set_custom_rect(RID p_item, bool p_custom_rect, const Rect2 &p_rect) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->custom_rect = p_custom_rect; @@ -521,35 +520,35 @@ void RendererCanvasCull::canvas_item_set_custom_rect(RID p_item, bool p_custom_r } void RendererCanvasCull::canvas_item_set_modulate(RID p_item, const Color &p_color) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->modulate = p_color; } void RendererCanvasCull::canvas_item_set_self_modulate(RID p_item, const Color &p_color) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->self_modulate = p_color; } void RendererCanvasCull::canvas_item_set_draw_behind_parent(RID p_item, bool p_enable) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->behind = p_enable; } void RendererCanvasCull::canvas_item_set_update_when_visible(RID p_item, bool p_update) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->update_when_visible = p_update; } void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPrimitive *line = canvas_item->alloc_command<Item::CommandPrimitive>(); @@ -573,7 +572,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from, void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) { ERR_FAIL_COND(p_points.size() < 2); - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Color color = Color(1, 1, 1, 1); @@ -714,7 +713,7 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width) { ERR_FAIL_COND(p_points.size() < 2); - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>(); @@ -730,7 +729,7 @@ void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Poin } void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>(); @@ -740,7 +739,7 @@ void RendererCanvasCull::canvas_item_add_rect(RID p_item, const Rect2 &p_rect, c } void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPolygon *circle = canvas_item->alloc_command<Item::CommandPolygon>(); @@ -776,7 +775,7 @@ void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos, } void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile, const Color &p_modulate, bool p_transpose) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>(); @@ -807,7 +806,7 @@ void RendererCanvasCull::canvas_item_add_texture_rect(RID p_item, const Rect2 &p } void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, int p_outline_size, float p_px_range) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>(); @@ -841,7 +840,7 @@ void RendererCanvasCull::canvas_item_add_msdf_texture_rect_region(RID p_item, co } void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate, bool p_transpose, bool p_clip_uv) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandRect *rect = canvas_item->alloc_command<Item::CommandRect>(); @@ -882,7 +881,7 @@ void RendererCanvasCull::canvas_item_add_texture_rect_region(RID p_item, const R } void RendererCanvasCull::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode, RS::NinePatchAxisMode p_y_axis_mode, bool p_draw_center, const Color &p_modulate) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandNinePatch *style = canvas_item->alloc_command<Item::CommandNinePatch>(); @@ -906,7 +905,7 @@ void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Poin uint32_t pc = p_points.size(); ERR_FAIL_COND(pc == 0 || pc > 4); - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandPrimitive *prim = canvas_item->alloc_command<Item::CommandPrimitive>(); @@ -932,7 +931,7 @@ void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Poin } void RendererCanvasCull::canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); #ifdef DEBUG_ENABLED int pointcount = p_points.size(); @@ -953,7 +952,7 @@ void RendererCanvasCull::canvas_item_add_polygon(RID p_item, const Vector<Point2 } void RendererCanvasCull::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, const Vector<int> &p_bones, const Vector<float> &p_weights, RID p_texture, int p_count) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); int vertex_count = p_points.size(); @@ -976,7 +975,7 @@ void RendererCanvasCull::canvas_item_add_triangle_array(RID p_item, const Vector } void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandTransform *tr = canvas_item->alloc_command<Item::CommandTransform>(); @@ -985,7 +984,7 @@ void RendererCanvasCull::canvas_item_add_set_transform(RID p_item, const Transfo } void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); ERR_FAIL_COND(!p_mesh.is_valid()); @@ -1004,7 +1003,7 @@ void RendererCanvasCull::canvas_item_add_mesh(RID p_item, const RID &p_mesh, con } void RendererCanvasCull::canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandParticles *part = canvas_item->alloc_command<Item::CommandParticles>(); @@ -1018,7 +1017,7 @@ void RendererCanvasCull::canvas_item_add_particles(RID p_item, RID p_particles, } void RendererCanvasCull::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandMultiMesh *mm = canvas_item->alloc_command<Item::CommandMultiMesh>(); @@ -1029,7 +1028,7 @@ void RendererCanvasCull::canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p } void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandClipIgnore *ci = canvas_item->alloc_command<Item::CommandClipIgnore>(); @@ -1038,7 +1037,7 @@ void RendererCanvasCull::canvas_item_add_clip_ignore(RID p_item, bool p_ignore) } void RendererCanvasCull::canvas_item_add_animation_slice(RID p_item, double p_animation_length, double p_slice_begin, double p_slice_end, double p_offset) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); Item::CommandAnimationSlice *as = canvas_item->alloc_command<Item::CommandAnimationSlice>(); @@ -1050,7 +1049,7 @@ void RendererCanvasCull::canvas_item_add_animation_slice(RID p_item, double p_an } void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_enable) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->sort_y = p_enable; @@ -1061,21 +1060,21 @@ void RendererCanvasCull::canvas_item_set_sort_children_by_y(RID p_item, bool p_e void RendererCanvasCull::canvas_item_set_z_index(RID p_item, int p_z) { ERR_FAIL_COND(p_z < RS::CANVAS_ITEM_Z_MIN || p_z > RS::CANVAS_ITEM_Z_MAX); - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->z_index = p_z; } void RendererCanvasCull::canvas_item_set_z_as_relative_to_parent(RID p_item, bool p_enable) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->z_relative = p_enable; } void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); if (canvas_item->skeleton == p_skeleton) { return; @@ -1104,7 +1103,7 @@ void RendererCanvasCull::canvas_item_attach_skeleton(RID p_item, RID p_skeleton) } void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_enable, const Rect2 &p_rect) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); if (p_enable && (canvas_item->copy_back_buffer == nullptr)) { canvas_item->copy_back_buffer = memnew(RendererCanvasRender::Item::CopyBackBuffer); @@ -1121,25 +1120,25 @@ void RendererCanvasCull::canvas_item_set_copy_to_backbuffer(RID p_item, bool p_e } void RendererCanvasCull::canvas_item_clear(RID p_item) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->clear(); } void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->index = p_index; if (canvas_item_owner.owns(canvas_item->parent)) { - Item *canvas_item_parent = canvas_item_owner.getornull(canvas_item->parent); + Item *canvas_item_parent = canvas_item_owner.get_or_null(canvas_item->parent); canvas_item_parent->children_order_dirty = true; return; } - Canvas *canvas = canvas_owner.getornull(canvas_item->parent); + Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent); if (canvas) { canvas->children_order_dirty = true; return; @@ -1147,21 +1146,21 @@ void RendererCanvasCull::canvas_item_set_draw_index(RID p_item, int p_index) { } void RendererCanvasCull::canvas_item_set_material(RID p_item, RID p_material) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->material = p_material; } void RendererCanvasCull::canvas_item_set_use_parent_material(RID p_item, bool p_enable) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); canvas_item->use_parent_material = p_enable; } void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_enable, const Rect2 &p_area, const Callable &p_enter_callable, const Callable &p_exit_callable) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); if (p_enable) { @@ -1181,7 +1180,7 @@ void RendererCanvasCull::canvas_item_set_visibility_notifier(RID p_item, bool p_ } void RendererCanvasCull::canvas_item_set_canvas_group_mode(RID p_item, RS::CanvasGroupMode p_mode, float p_clear_margin, bool p_fit_empty, float p_fit_margin, bool p_blur_mipmaps) { - Item *canvas_item = canvas_item_owner.getornull(p_item); + Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!canvas_item); if (p_mode == RS::CANVAS_GROUP_MODE_DISABLED) { @@ -1206,12 +1205,12 @@ RID RendererCanvasCull::canvas_light_allocate() { } void RendererCanvasCull::canvas_light_initialize(RID p_rid) { canvas_light_owner.initialize_rid(p_rid); - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_rid); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_rid); clight->light_internal = RSG::canvas_render->light_create(); } void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode p_mode) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); if (clight->mode == p_mode) { @@ -1232,11 +1231,11 @@ void RendererCanvasCull::canvas_light_set_mode(RID p_light, RS::CanvasLightMode } void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); if (clight->canvas.is_valid()) { - Canvas *canvas = canvas_owner.getornull(clight->canvas); + Canvas *canvas = canvas_owner.get_or_null(clight->canvas); if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) { canvas->lights.erase(clight); } else { @@ -1251,7 +1250,7 @@ void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas clight->canvas = p_canvas; if (clight->canvas.is_valid()) { - Canvas *canvas = canvas_owner.getornull(clight->canvas); + Canvas *canvas = canvas_owner.get_or_null(clight->canvas); if (clight->mode == RS::CANVAS_LIGHT_MODE_POINT) { canvas->lights.insert(clight); } else { @@ -1261,28 +1260,28 @@ void RendererCanvasCull::canvas_light_attach_to_canvas(RID p_light, RID p_canvas } void RendererCanvasCull::canvas_light_set_enabled(RID p_light, bool p_enabled) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->enabled = p_enabled; } void RendererCanvasCull::canvas_light_set_texture_scale(RID p_light, float p_scale) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->scale = p_scale; } void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform2D &p_transform) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->xform = p_transform; } void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); if (clight->texture == p_texture) { @@ -1294,35 +1293,35 @@ void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) { } void RendererCanvasCull::canvas_light_set_texture_offset(RID p_light, const Vector2 &p_offset) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->texture_offset = p_offset; } void RendererCanvasCull::canvas_light_set_color(RID p_light, const Color &p_color) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->color = p_color; } void RendererCanvasCull::canvas_light_set_height(RID p_light, float p_height) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->height = p_height; } void RendererCanvasCull::canvas_light_set_energy(RID p_light, float p_energy) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->energy = p_energy; } void RendererCanvasCull::canvas_light_set_z_range(RID p_light, int p_min_z, int p_max_z) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->z_min = p_min_z; @@ -1330,7 +1329,7 @@ void RendererCanvasCull::canvas_light_set_z_range(RID p_light, int p_min_z, int } void RendererCanvasCull::canvas_light_set_layer_range(RID p_light, int p_min_layer, int p_max_layer) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->layer_max = p_max_layer; @@ -1338,35 +1337,35 @@ void RendererCanvasCull::canvas_light_set_layer_range(RID p_light, int p_min_lay } void RendererCanvasCull::canvas_light_set_item_cull_mask(RID p_light, int p_mask) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->item_mask = p_mask; } void RendererCanvasCull::canvas_light_set_item_shadow_cull_mask(RID p_light, int p_mask) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->item_shadow_mask = p_mask; } void RendererCanvasCull::canvas_light_set_directional_distance(RID p_light, float p_distance) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->directional_distance = p_distance; } void RendererCanvasCull::canvas_light_set_blend_mode(RID p_light, RS::CanvasLightBlendMode p_mode) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->blend_mode = p_mode; } void RendererCanvasCull::canvas_light_set_shadow_enabled(RID p_light, bool p_enabled) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); if (clight->use_shadow == p_enabled) { @@ -1378,21 +1377,21 @@ void RendererCanvasCull::canvas_light_set_shadow_enabled(RID p_light, bool p_ena } void RendererCanvasCull::canvas_light_set_shadow_filter(RID p_light, RS::CanvasLightShadowFilter p_filter) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->shadow_filter = p_filter; } void RendererCanvasCull::canvas_light_set_shadow_color(RID p_light, const Color &p_color) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->shadow_color = p_color; } void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smooth) { - RendererCanvasRender::Light *clight = canvas_light_owner.getornull(p_light); + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_COND(!clight); clight->shadow_smooth = p_smooth; } @@ -1405,11 +1404,11 @@ void RendererCanvasCull::canvas_light_occluder_initialize(RID p_rid) { } void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, RID p_canvas) { - RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_COND(!occluder); if (occluder->canvas.is_valid()) { - Canvas *canvas = canvas_owner.getornull(occluder->canvas); + Canvas *canvas = canvas_owner.get_or_null(occluder->canvas); canvas->occluders.erase(occluder); } @@ -1420,24 +1419,24 @@ void RendererCanvasCull::canvas_light_occluder_attach_to_canvas(RID p_occluder, occluder->canvas = p_canvas; if (occluder->canvas.is_valid()) { - Canvas *canvas = canvas_owner.getornull(occluder->canvas); + Canvas *canvas = canvas_owner.get_or_null(occluder->canvas); canvas->occluders.insert(occluder); } } void RendererCanvasCull::canvas_light_occluder_set_enabled(RID p_occluder, bool p_enabled) { - RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_COND(!occluder); occluder->enabled = p_enabled; } void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p_polygon) { - RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_COND(!occluder); if (occluder->polygon.is_valid()) { - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_polygon); if (occluder_poly) { occluder_poly->owners.erase(occluder); } @@ -1447,7 +1446,7 @@ void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p occluder->occluder = RID(); if (occluder->polygon.is_valid()) { - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_polygon); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_polygon); if (!occluder_poly) { occluder->polygon = RID(); ERR_FAIL_COND(!occluder_poly); @@ -1461,19 +1460,19 @@ void RendererCanvasCull::canvas_light_occluder_set_polygon(RID p_occluder, RID p } void RendererCanvasCull::canvas_light_occluder_set_as_sdf_collision(RID p_occluder, bool p_enable) { - RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_COND(!occluder); } void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) { - RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_COND(!occluder); occluder->xform = p_xform; } void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) { - RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_occluder); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_COND(!occluder); occluder->light_mask = p_mask; @@ -1484,12 +1483,12 @@ RID RendererCanvasCull::canvas_occluder_polygon_allocate() { } void RendererCanvasCull::canvas_occluder_polygon_initialize(RID p_rid) { canvas_light_occluder_polygon_owner.initialize_rid(p_rid); - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_rid); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_rid); occluder_poly->occluder = RSG::canvas_render->occluder_polygon_create(); } void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygon, const Vector<Vector2> &p_shape, bool p_closed) { - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_occluder_polygon); ERR_FAIL_COND(!occluder_poly); uint32_t pc = p_shape.size(); @@ -1513,7 +1512,7 @@ void RendererCanvasCull::canvas_occluder_polygon_set_shape(RID p_occluder_polygo } void RendererCanvasCull::canvas_occluder_polygon_set_cull_mode(RID p_occluder_polygon, RS::CanvasOccluderPolygonCullMode p_mode) { - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_occluder_polygon); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_occluder_polygon); ERR_FAIL_COND(!occluder_poly); occluder_poly->cull_mode = p_mode; RSG::canvas_render->occluder_polygon_set_cull_mode(occluder_poly->occluder, p_mode); @@ -1550,12 +1549,12 @@ void RendererCanvasCull::canvas_texture_set_texture_repeat(RID p_canvas_texture, } void RendererCanvasCull::canvas_item_set_default_texture_filter(RID p_item, RS::CanvasItemTextureFilter p_filter) { - Item *ci = canvas_item_owner.getornull(p_item); + Item *ci = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!ci); ci->texture_filter = p_filter; } void RendererCanvasCull::canvas_item_set_default_texture_repeat(RID p_item, RS::CanvasItemTextureRepeat p_repeat) { - Item *ci = canvas_item_owner.getornull(p_item); + Item *ci = canvas_item_owner.get_or_null(p_item); ERR_FAIL_COND(!ci); ci->texture_repeat = p_repeat; } @@ -1600,11 +1599,11 @@ void RendererCanvasCull::update_visibility_notifiers() { bool RendererCanvasCull::free(RID p_rid) { if (canvas_owner.owns(p_rid)) { - Canvas *canvas = canvas_owner.getornull(p_rid); + Canvas *canvas = canvas_owner.get_or_null(p_rid); ERR_FAIL_COND_V(!canvas, false); while (canvas->viewports.size()) { - RendererViewport::Viewport *vp = RSG::viewport->viewport_owner.getornull(canvas->viewports.front()->get()); + RendererViewport::Viewport *vp = RSG::viewport->viewport_owner.get_or_null(canvas->viewports.front()->get()); ERR_FAIL_COND_V(!vp, true); Map<RID, RendererViewport::Viewport::CanvasData>::Element *E = vp->canvas_map.find(p_rid); @@ -1629,15 +1628,15 @@ bool RendererCanvasCull::free(RID p_rid) { canvas_owner.free(p_rid); } else if (canvas_item_owner.owns(p_rid)) { - Item *canvas_item = canvas_item_owner.getornull(p_rid); + Item *canvas_item = canvas_item_owner.get_or_null(p_rid); ERR_FAIL_COND_V(!canvas_item, true); if (canvas_item->parent.is_valid()) { if (canvas_owner.owns(canvas_item->parent)) { - Canvas *canvas = canvas_owner.getornull(canvas_item->parent); + Canvas *canvas = canvas_owner.get_or_null(canvas_item->parent); canvas->erase_item(canvas_item); } else if (canvas_item_owner.owns(canvas_item->parent)) { - Item *item_owner = canvas_item_owner.getornull(canvas_item->parent); + Item *item_owner = canvas_item_owner.get_or_null(canvas_item->parent); item_owner->child_items.erase(canvas_item); if (item_owner->sort_y) { @@ -1663,11 +1662,11 @@ bool RendererCanvasCull::free(RID p_rid) { canvas_item_owner.free(p_rid); } else if (canvas_light_owner.owns(p_rid)) { - RendererCanvasRender::Light *canvas_light = canvas_light_owner.getornull(p_rid); + RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_COND_V(!canvas_light, true); if (canvas_light->canvas.is_valid()) { - Canvas *canvas = canvas_owner.getornull(canvas_light->canvas); + Canvas *canvas = canvas_owner.get_or_null(canvas_light->canvas); if (canvas) { canvas->lights.erase(canvas_light); } @@ -1678,25 +1677,25 @@ bool RendererCanvasCull::free(RID p_rid) { canvas_light_owner.free(p_rid); } else if (canvas_light_occluder_owner.owns(p_rid)) { - RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.getornull(p_rid); + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid); ERR_FAIL_COND_V(!occluder, true); if (occluder->polygon.is_valid()) { - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(occluder->polygon); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon); if (occluder_poly) { occluder_poly->owners.erase(occluder); } } if (occluder->canvas.is_valid() && canvas_owner.owns(occluder->canvas)) { - Canvas *canvas = canvas_owner.getornull(occluder->canvas); + Canvas *canvas = canvas_owner.get_or_null(occluder->canvas); canvas->occluders.erase(occluder); } canvas_light_occluder_owner.free(p_rid); } else if (canvas_light_occluder_polygon_owner.owns(p_rid)) { - LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.getornull(p_rid); + LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(p_rid); ERR_FAIL_COND_V(!occluder_poly, true); RSG::canvas_render->free(occluder_poly->occluder); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 5e343dcf02..bdd61123df 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -152,7 +152,7 @@ public: void erase_item(Item *p_item) { int idx = find_item(p_item); if (idx >= 0) { - child_items.remove(idx); + child_items.remove_at(idx); } } @@ -315,4 +315,4 @@ public: ~RendererCanvasCull(); }; -#endif // VISUALSERVERCANVAS_H +#endif // RENDERING_SERVER_CANVAS_CULL_H diff --git a/servers/rendering/renderer_compositor.h b/servers/rendering/renderer_compositor.h index 6206849b66..4526354d17 100644 --- a/servers/rendering/renderer_compositor.h +++ b/servers/rendering/renderer_compositor.h @@ -41,7 +41,8 @@ class RendererSceneRender; struct BlitToScreen { RID render_target; - Rect2i rect; + Rect2 src_rect = Rect2(0.0, 0.0, 1.0, 1.0); + Rect2i dst_rect; struct { bool use_layer = false; @@ -66,6 +67,7 @@ private: protected: static RendererCompositor *(*_create_func)(); + bool back_end = false; public: static RendererCompositor *create(); @@ -87,7 +89,7 @@ public: virtual uint64_t get_frame_number() const = 0; virtual double get_frame_delta_time() const = 0; - virtual bool is_low_end() const = 0; + _FORCE_INLINE_ virtual bool is_low_end() const { return back_end; }; virtual bool is_xr_enabled() const; RendererCompositor(); diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.h b/servers/rendering/renderer_rd/cluster_builder_rd.h index c0c03eb26a..feafd4c2db 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.h +++ b/servers/rendering/renderer_rd/cluster_builder_rd.h @@ -289,7 +289,7 @@ public: e.touches_near = min_d < z_near; } else { //contains camera inside light - Plane base_plane(xform.origin, -xform.basis.get_axis(Vector3::AXIS_Z)); + Plane base_plane(-xform.basis.get_axis(Vector3::AXIS_Z), xform.origin); float dist = base_plane.distance_to(Vector3()); if (dist >= 0 && dist < radius) { //inside, check angle diff --git a/servers/rendering/renderer_rd/effects_rd.cpp b/servers/rendering/renderer_rd/effects_rd.cpp index 236eb5e596..cf943901d4 100644 --- a/servers/rendering/renderer_rd/effects_rd.cpp +++ b/servers/rendering/renderer_rd/effects_rd.cpp @@ -237,6 +237,43 @@ RID EffectsRD::_get_compute_uniform_set_from_image_pair(RID p_texture1, RID p_te return uniform_set; } +void EffectsRD::fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness) { + memset(&FSR_upscale.push_constant, 0, sizeof(FSRUpscalePushConstant)); + + int dispatch_x = (p_size.x + 15) / 16; + int dispatch_y = (p_size.y + 15) / 16; + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, FSR_upscale.pipeline); + + FSR_upscale.push_constant.resolution_width = p_internal_size.width; + FSR_upscale.push_constant.resolution_height = p_internal_size.height; + FSR_upscale.push_constant.upscaled_width = p_size.width; + FSR_upscale.push_constant.upscaled_height = p_size.height; + FSR_upscale.push_constant.sharpness = p_fsr_upscale_sharpness; + + //FSR Easc + FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_EASU; + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_source_rd_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_secondary_texture), 1); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1); + RD::get_singleton()->compute_list_add_barrier(compute_list); + + //FSR Rcas + FSR_upscale.push_constant.pass = FSR_UPSCALE_PASS_RCAS; + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_compute_uniform_set_from_texture(p_secondary_texture), 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, _get_uniform_set_from_image(p_destination_texture), 1); + + RD::get_singleton()->compute_list_set_push_constant(compute_list, &FSR_upscale.push_constant, sizeof(FSRUpscalePushConstant)); + + RD::get_singleton()->compute_list_dispatch(compute_list, dispatch_x, dispatch_y, 1); + + RD::get_singleton()->compute_list_end(compute_list); +} + void EffectsRD::copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y, bool p_panorama) { memset(©_to_fb.push_constant, 0, sizeof(CopyToFbPushConstant)); @@ -443,7 +480,7 @@ void EffectsRD::gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back RD::get_singleton()->compute_list_end(); } -void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { +void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { ERR_FAIL_COND_MSG(prefer_raster_effects, "Can't use the compute version of the gaussian glow with the mobile renderer."); memset(©.push_constant, 0, sizeof(CopyPushConstant)); @@ -456,7 +493,7 @@ void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const copy.push_constant.glow_strength = p_strength; copy.push_constant.glow_bloom = p_bloom; - copy.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold; + copy.push_constant.glow_hdr_threshold = p_hdr_bleed_threshold; copy.push_constant.glow_hdr_scale = p_hdr_bleed_scale; copy.push_constant.glow_exposure = p_exposure; copy.push_constant.glow_white = 0; //actually unused @@ -479,7 +516,7 @@ void EffectsRD::gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const RD::get_singleton()->compute_list_end(); } -void EffectsRD::gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_treshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { +void EffectsRD::gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength, bool p_high_quality, bool p_first_pass, float p_luminance_cap, float p_exposure, float p_bloom, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, RID p_auto_exposure, float p_auto_exposure_grey) { ERR_FAIL_COND_MSG(!prefer_raster_effects, "Can't use the raster version of the gaussian glow with the clustered renderer."); memset(&blur_raster.push_constant, 0, sizeof(BlurRasterPushConstant)); @@ -492,7 +529,7 @@ void EffectsRD::gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_ blur_raster.push_constant.glow_strength = p_strength; blur_raster.push_constant.glow_bloom = p_bloom; - blur_raster.push_constant.glow_hdr_threshold = p_hdr_bleed_treshold; + blur_raster.push_constant.glow_hdr_threshold = p_hdr_bleed_threshold; blur_raster.push_constant.glow_hdr_scale = p_hdr_bleed_scale; blur_raster.push_constant.glow_exposure = p_exposure; blur_raster.push_constant.glow_white = 0; //actually unused @@ -1400,6 +1437,7 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep ssao.gather_push_constant.half_screen_pixel_size_x025[0] = ssao.gather_push_constant.half_screen_pixel_size[0] * 0.25; ssao.gather_push_constant.half_screen_pixel_size_x025[1] = ssao.gather_push_constant.half_screen_pixel_size[1] * 0.25; + ssao.gather_push_constant.radius = p_settings.radius; float radius_near_limit = (p_settings.radius * 1.2f); if (p_settings.quality <= RS::ENV_SSAO_QUALITY_LOW) { radius_near_limit *= 1.50f; @@ -1407,12 +1445,8 @@ void EffectsRD::generate_ssao(RID p_depth_buffer, RID p_normal_buffer, RID p_dep if (p_settings.quality == RS::ENV_SSAO_QUALITY_VERY_LOW) { ssao.gather_push_constant.radius *= 0.8f; } - if (p_settings.half_size) { - ssao.gather_push_constant.radius *= 0.5f; - } } radius_near_limit /= tan_half_fov_y; - ssao.gather_push_constant.radius = p_settings.radius; ssao.gather_push_constant.intensity = p_settings.intensity; ssao.gather_push_constant.shadow_power = p_settings.power; ssao.gather_push_constant.shadow_clamp = 0.98; @@ -1891,6 +1925,27 @@ void EffectsRD::sort_buffer(RID p_uniform_set, int p_size) { } EffectsRD::EffectsRD(bool p_prefer_raster_effects) { + { + Vector<String> FSR_upscale_modes; + +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + // MoltenVK does not support some of the operations used by the normal mode of FSR. Fallback works just fine though. + FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n"); +#else + // Everyone else can use normal mode when available. + if (RD::get_singleton()->get_device_capabilities()->supports_fsr_half_float) { + FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_NORMAL\n"); + } else { + FSR_upscale_modes.push_back("\n#define MODE_FSR_UPSCALE_FALLBACK\n"); + } +#endif + + FSR_upscale.shader.initialize(FSR_upscale_modes); + + FSR_upscale.shader_version = FSR_upscale.shader.version_create(); + FSR_upscale.pipeline = RD::get_singleton()->compute_pipeline_create(FSR_upscale.shader.version_get_shader(FSR_upscale.shader_version, 0)); + } + prefer_raster_effects = p_prefer_raster_effects; if (prefer_raster_effects) { @@ -2526,6 +2581,7 @@ EffectsRD::~EffectsRD() { RD::get_singleton()->free(index_buffer); //array gets freed as dependency RD::get_singleton()->free(filter.coefficient_buffer); + FSR_upscale.shader.version_free(FSR_upscale.shader_version); if (prefer_raster_effects) { blur_raster.shader.version_free(blur_raster.shader_version); bokeh.raster_shader.version_free(blur_raster.shader_version); diff --git a/servers/rendering/renderer_rd/effects_rd.h b/servers/rendering/renderer_rd/effects_rd.h index 0db0919dbc..6037127e82 100644 --- a/servers/rendering/renderer_rd/effects_rd.h +++ b/servers/rendering/renderer_rd/effects_rd.h @@ -45,6 +45,7 @@ #include "servers/rendering/renderer_rd/shaders/cubemap_filter_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cubemap_roughness.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/cubemap_roughness_raster.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/fsr_upscale.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/luminance_reduce.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/luminance_reduce_raster.glsl.gen.h" #include "servers/rendering/renderer_rd/shaders/resolve.glsl.gen.h" @@ -69,6 +70,28 @@ class EffectsRD { private: bool prefer_raster_effects; + enum FSRUpscalePass { + FSR_UPSCALE_PASS_EASU = 0, + FSR_UPSCALE_PASS_RCAS = 1 + }; + + struct FSRUpscalePushConstant { + float resolution_width; + float resolution_height; + float upscaled_width; + float upscaled_height; + float sharpness; + int pass; + int _unused0, _unused1; + }; + + struct FSRUpscale { + FSRUpscalePushConstant push_constant; + FsrUpscaleShaderRD shader; + RID shader_version; + RID pipeline; + } FSR_upscale; + enum BlurRasterMode { BLUR_MIPMAP, @@ -754,6 +777,7 @@ private: public: bool get_prefer_raster_effects(); + void fsr_upscale(RID p_source_rd_texture, RID p_secondary_texture, RID p_destination_texture, const Size2i &p_internal_size, const Size2i &p_size, float p_fsr_upscale_sharpness); void copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_alpha_to_zero = false, bool p_srgb = false, RID p_secondary = RID()); void copy_to_rect(RID p_source_rd_texture, RID p_dest_texture, const Rect2i &p_rect, bool p_flip_y = false, bool p_force_luminance = false, bool p_all_source = false, bool p_8_bit_dst = false, bool p_alpha_to_one = false); void copy_cubemap_to_panorama(RID p_source_cube, RID p_dest_panorama, const Size2i &p_panorama_size, float p_lod, bool p_is_array); @@ -762,8 +786,8 @@ public: void copy_to_atlas_fb(RID p_source_rd_texture, RID p_dest_framebuffer, const Rect2 &p_uv_rect, RD::DrawListID p_draw_list, bool p_flip_y = false, bool p_panorama = false); void gaussian_blur(RID p_source_rd_texture, RID p_texture, RID p_back_texture, const Rect2i &p_region, bool p_8bit_dst = false); void set_color(RID p_dest_texture, const Color &p_color, const Rect2i &p_region, bool p_8bit_dst = false); - void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); - void gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_treshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); + void gaussian_glow(RID p_source_rd_texture, RID p_back_texture, const Size2i &p_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); + void gaussian_glow_raster(RID p_source_rd_texture, RID p_framebuffer_half, RID p_rd_texture_half, RID p_dest_framebuffer, const Vector2 &p_pixel_size, float p_strength = 1.0, bool p_high_quality = false, bool p_first_pass = false, float p_luminance_cap = 16.0, float p_exposure = 1.0, float p_bloom = 0.0, float p_hdr_bleed_threshold = 1.0, float p_hdr_bleed_scale = 1.0, RID p_auto_exposure = RID(), float p_auto_exposure_grey = 1.0); void cubemap_roughness(RID p_source_rd_texture, RID p_dest_texture, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); void cubemap_roughness_raster(RID p_source_rd_texture, RID p_dest_framebuffer, uint32_t p_face_id, uint32_t p_sample_count, float p_roughness, float p_size); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp index 1b730567d9..03ce2690bf 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -223,7 +223,6 @@ void RenderForwardClustered::RenderBufferDataForwardClustered::configure(RID p_c RD::TEXTURE_SAMPLES_2, RD::TEXTURE_SAMPLES_4, RD::TEXTURE_SAMPLES_8, - RD::TEXTURE_SAMPLES_16 }; texture_samples = ts[p_msaa]; @@ -329,10 +328,20 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p push_constant.uv_offset = 0; } + bool should_request_redraw = false; + for (uint32_t i = p_from_element; i < p_to_element; i++) { const GeometryInstanceSurfaceDataCache *surf = p_params->elements[i]; const RenderElementInfo &element_info = p_params->element_info[i]; + if ((p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_SPECULAR) && !(surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { + continue; // Objects with "Depth-prepass" transparency are included in both render lists, but should only be rendered in the transparent pass + } + + if (surf->owner->instance_count == 0) { + continue; + } + push_constant.base_index = i + p_params->element_offset; RID material_uniform_set; @@ -366,6 +375,11 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p continue; } + //request a redraw if one of the shaders uses TIME + if (shader->uses_time) { + should_request_redraw = true; + } + //find cull variant SceneShaderForwardClustered::ShaderData::CullVariant cull_variant; @@ -382,7 +396,7 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p RS::PrimitiveType primitive = surf->primitive; RID xforms_uniform_set = surf->owner->transforms_uniform_set; - SceneShaderForwardClustered::ShaderVersion shader_version = SceneShaderForwardClustered::SHADER_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. + SceneShaderForwardClustered::PipelineVersion pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_MAX; // Assigned to silence wrong -Wmaybe-initialized. uint32_t pipeline_specialization = 0; @@ -400,48 +414,54 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p } switch (p_pass_mode) { - case PASS_MODE_COLOR: + case PASS_MODE_COLOR: { + if (element_info.uses_lightmap) { + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS; + } else { + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_OPAQUE_PASS; + } + } break; case PASS_MODE_COLOR_TRANSPARENT: { if (element_info.uses_lightmap) { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_LIGHTMAP_TRANSPARENT_PASS; } else { if (element_info.uses_forward_gi) { pipeline_specialization |= SceneShaderForwardClustered::SHADER_SPECIALIZATION_FORWARD_GI; } - shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_TRANSPARENT_PASS; } } break; case PASS_MODE_COLOR_SPECULAR: { if (element_info.uses_lightmap) { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS_WITH_SEPARATE_SPECULAR; } else { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_OPAQUE_PASS_WITH_SEPARATE_SPECULAR; } } break; case PASS_MODE_SHADOW: case PASS_MODE_DEPTH: { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS; } break; case PASS_MODE_SHADOW_DP: { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_DP; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_DP; } break; case PASS_MODE_DEPTH_NORMAL_ROUGHNESS: { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS; } break; case PASS_MODE_DEPTH_NORMAL_ROUGHNESS_VOXEL_GI: { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI; } break; case PASS_MODE_DEPTH_MATERIAL: { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL; } break; case PASS_MODE_SDF: { - shader_version = SceneShaderForwardClustered::SHADER_VERSION_DEPTH_PASS_WITH_SDF; + pipeline_version = SceneShaderForwardClustered::PIPELINE_VERSION_DEPTH_PASS_WITH_SDF; } break; } PipelineCacheRD *pipeline = nullptr; - pipeline = &shader->pipelines[cull_variant][primitive][shader_version]; + pipeline = &shader->pipelines[cull_variant][primitive][pipeline_version]; RD::VertexFormatID vertex_format = -1; RID vertex_array_rd; @@ -501,6 +521,11 @@ void RenderForwardClustered::_render_list_template(RenderingDevice::DrawListID p RD::get_singleton()->draw_list_draw(draw_list, index_array_rd.is_valid(), instance_count); i += element_info.repeat - 1; //skip equal elements } + + // Make the actual redraw request + if (should_request_redraw) { + RenderingServerDefault::redraw_request(); + } } void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element) { @@ -754,19 +779,10 @@ void RenderForwardClustered::_setup_environment(const RenderDataRD *p_render_dat scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment); scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment); - Color ao_color = environment_get_ao_color(p_render_data->environment).to_linear(); - scene_state.ubo.ao_color[0] = ao_color.r; - scene_state.ubo.ao_color[1] = ao_color.g; - scene_state.ubo.ao_color[2] = ao_color.b; - scene_state.ubo.ao_color[3] = ao_color.a; - scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment); scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment); scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment); scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment); - if (scene_state.ubo.fog_height_density >= 0.0001) { - scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density; - } scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment); Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear(); @@ -914,7 +930,7 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con } uint32_t lightmap_captures_used = 0; - Plane near_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z)); + Plane near_plane = Plane(-p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z), p_render_data->cam_transform.origin); near_plane.d += p_render_data->cam_projection.get_z_near(); float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near(); @@ -944,10 +960,23 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con } bool uses_lightmap = false; bool uses_gi = false; + float fade_alpha = 1.0; + + if (inst->fade_near || inst->fade_far) { + float fade_dist = inst->transform.origin.distance_to(p_render_data->cam_transform.origin); + if (inst->fade_far && fade_dist > inst->fade_far_begin) { + fade_alpha = MAX(0.0, 1.0 - (fade_dist - inst->fade_far_begin) / (inst->fade_far_end - inst->fade_far_begin)); + } else if (inst->fade_near && fade_dist < inst->fade_near_end) { + fade_alpha = MAX(0.0, (fade_dist - inst->fade_near_begin) / (inst->fade_near_end - inst->fade_near_begin)); + } + } - if (p_render_list == RENDER_LIST_OPAQUE) { - //setup GI + fade_alpha *= inst->force_alpha * inst->parent_fade_alpha; + flags = (flags & ~INSTANCE_DATA_FLAGS_FADE_MASK) | (uint32_t(fade_alpha * 255.0) << INSTANCE_DATA_FLAGS_FADE_SHIFT); + + if (p_render_list == RENDER_LIST_OPAQUE) { + // Setup GI if (inst->lightmap_instance.is_valid()) { int32_t lightmap_cull_index = -1; for (uint32_t j = 0; j < scene_state.lightmaps_used; j++) { @@ -1078,6 +1107,11 @@ void RenderForwardClustered::_fill_render_list(RenderListType p_render_list, con #else bool force_alpha = false; #endif + + if (fade_alpha < 0.999) { + force_alpha = true; + } + if (!force_alpha && (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE))) { rl->add_element(surf); } @@ -1163,7 +1197,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co render_buffer = (RenderBufferDataForwardClustered *)render_buffers_get_data(p_render_data->render_buffers); } RendererSceneEnvironmentRD *env = get_environment(p_render_data->environment); - static const int texture_multisamples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8, 16 }; + static const int texture_multisamples[RS::VIEWPORT_MSAA_MAX] = { 1, 2, 4, 8 }; //first of all, make a new render pass //fill up ubo @@ -1176,6 +1210,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co scene_state.ubo.viewport_size[0] = vp_he.x; scene_state.ubo.viewport_size[1] = vp_he.y; scene_state.ubo.directional_light_count = 0; + scene_state.ubo.opaque_prepass_threshold = 0.99f; Size2i screen_size; RID opaque_framebuffer; @@ -1419,6 +1454,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); scene_state.ubo.directional_light_count = p_render_data->directional_light_count; + scene_state.ubo.opaque_prepass_threshold = 0.0f; _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, p_render_data->render_buffers.is_valid()); @@ -1552,7 +1588,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co _setup_environment(p_render_data, p_render_data->reflection_probe.is_valid(), screen_size, !p_render_data->reflection_probe.is_valid(), p_default_bg_color, false); { - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), false, PASS_MODE_COLOR_TRANSPARENT, render_buffer == nullptr, p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold); _render_list_with_threads(&render_list_params, alpha_framebuffer, can_continue_color ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ, can_continue_depth ? RD::INITIAL_ACTION_CONTINUE : RD::INITIAL_ACTION_KEEP, RD::FINAL_ACTION_READ); } @@ -1602,6 +1638,7 @@ void RenderForwardClustered::_render_shadow_append(RID p_framebuffer, const Page render_data.render_info = p_render_info; scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; + scene_state.ubo.opaque_prepass_threshold = 0.1f; _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index); @@ -1688,6 +1725,7 @@ void RenderForwardClustered::_render_particle_collider_heightfield(RID p_fb, con _update_render_base_uniform_set(); scene_state.ubo.dual_paraboloid_side = 0; + scene_state.ubo.opaque_prepass_threshold = 0.0; _setup_environment(&render_data, true, Vector2(1, 1), true, Color(), false, false); @@ -1725,6 +1763,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform scene_state.ubo.dual_paraboloid_side = 0; scene_state.ubo.material_uv2_mode = false; + scene_state.ubo.opaque_prepass_threshold = 0.0f; _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); @@ -1768,6 +1807,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<GeometryInstance *> &p scene_state.ubo.dual_paraboloid_side = 0; scene_state.ubo.material_uv2_mode = true; + scene_state.ubo.opaque_prepass_threshold = 0.0; _setup_environment(&render_data, true, Vector2(1, 1), false, Color()); @@ -1914,7 +1954,9 @@ void RenderForwardClustered::_base_uniforms_changed() { } void RenderForwardClustered::_update_render_base_uniform_set() { - if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version())) { + if (render_base_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set) || (lightmap_texture_array_version != storage->lightmap_array_get_version()) || base_uniform_set_updated) { + base_uniform_set_updated = false; + if (render_base_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(render_base_uniform_set)) { RD::get_singleton()->free(render_base_uniform_set); } @@ -1929,18 +1971,18 @@ void RenderForwardClustered::_update_render_base_uniform_set() { u.binding = 1; u.ids.resize(12); RID *ids_ptr = u.ids.ptrw(); - ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); - ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); - ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[0] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[1] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[2] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[3] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[4] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[5] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[6] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[7] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[8] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[9] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[10] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[11] = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); uniforms.push_back(u); } @@ -1959,19 +2001,19 @@ void RenderForwardClustered::_update_render_base_uniform_set() { RID sampler; switch (decals_get_filter()) { case RS::DECAL_FILTER_NEAREST: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::DECAL_FILTER_NEAREST_MIPMAPS: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::DECAL_FILTER_LINEAR: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::DECAL_FILTER_LINEAR_MIPMAPS: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::DECAL_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; } @@ -1986,19 +2028,19 @@ void RenderForwardClustered::_update_render_base_uniform_set() { RID sampler; switch (light_projectors_get_filter()) { case RS::LIGHT_PROJECTOR_FILTER_NEAREST: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::LIGHT_PROJECTOR_FILTER_NEAREST_MIPMAPS: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::LIGHT_PROJECTOR_FILTER_LINEAR: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; case RS::LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS_ANISOTROPIC: { - sampler = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + sampler = storage->sampler_rd_get_custom(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); } break; } @@ -2552,7 +2594,7 @@ void RenderForwardClustered::_geometry_instance_add_surface_with_material(Geomet SceneShaderForwardClustered::MaterialData *material_shadow = nullptr; void *surface_shadow = nullptr; - if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { + if (!p_material->shader_data->uses_particle_trails && !p_material->shader_data->writes_modelview_or_projection && !p_material->shader_data->uses_vertex && !p_material->shader_data->uses_position && !p_material->shader_data->uses_discard && !p_material->shader_data->uses_depth_pre_pass) { flags |= GeometryInstanceSurfaceDataCache::FLAG_USES_SHARED_SHADOW_MATERIAL; material_shadow = (SceneShaderForwardClustered::MaterialData *)storage->material_get_data(scene_shader.default_material, RendererStorageRD::SHADER_TYPE_3D); @@ -2696,7 +2738,7 @@ void RenderForwardClustered::_geometry_instance_update(GeometryInstance *p_geome } break; #if 0 case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base); ERR_CONTINUE(!immediate); _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); @@ -2888,6 +2930,29 @@ void RenderForwardClustered::geometry_instance_set_lod_bias(GeometryInstance *p_ ERR_FAIL_COND(!ginstance); ginstance->lod_bias = p_lod_bias; } +void RenderForwardClustered::geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) { + GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->fade_near = p_enable_near; + ginstance->fade_near_begin = p_near_begin; + ginstance->fade_near_end = p_near_end; + ginstance->fade_far = p_enable_far; + ginstance->fade_far_begin = p_far_begin; + ginstance->fade_far_end = p_far_end; +} + +void RenderForwardClustered::geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) { + GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->parent_fade_alpha = p_alpha; +} + +void RenderForwardClustered::geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) { + GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); + ERR_FAIL_COND(!ginstance); + ginstance->force_alpha = CLAMP(1.0 - p_transparency, 0, 1); +} + void RenderForwardClustered::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { GeometryInstanceForwardClustered *ginstance = static_cast<GeometryInstanceForwardClustered *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h index 676f633d33..d6ab4d1db2 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -129,6 +129,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { virtual void _base_uniforms_changed() override; virtual RID _render_buffers_get_normal_texture(RID p_render_buffers) override; + bool base_uniform_set_updated = false; void _update_render_base_uniform_set(); RID _setup_sdfgi_render_pass_uniform_set(RID p_albedo_texture, RID p_emission_texture, RID p_emission_aniso_texture, RID p_geom_facing_texture); RID _setup_render_pass_uniform_set(RenderListType p_render_list, const RenderDataRD *p_render_data, RID p_radiance_texture, bool p_use_directional_shadow_atlas = false, int p_index = 0); @@ -208,6 +209,8 @@ class RenderForwardClustered : public RendererSceneRenderRD { INSTANCE_DATA_FLAG_MULTIMESH_HAS_CUSTOM_DATA = 1 << 15, INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_SHIFT = 16, INSTANCE_DATA_FLAGS_PARTICLE_TRAIL_MASK = 0xFF, + INSTANCE_DATA_FLAGS_FADE_SHIFT = 24, + INSTANCE_DATA_FLAGS_FADE_MASK = 0xFF << INSTANCE_DATA_FLAGS_FADE_SHIFT }; struct SceneState { @@ -255,9 +258,8 @@ class RenderForwardClustered : public RendererSceneRenderRD { float roughness_limiter_amount; float roughness_limiter_limit; - uint32_t roughness_limiter_pad[2]; - - float ao_color[4]; + float opaque_prepass_threshold; + uint32_t roughness_limiter_pad; float sdf_to_bounds[16]; @@ -468,6 +470,15 @@ class RenderForwardClustered : public RendererSceneRenderRD { bool can_sdfgi = false; bool using_projectors = false; bool using_softshadows = false; + bool fade_near = false; + float fade_near_begin = 0; + float fade_near_end = 0; + bool fade_far = false; + float fade_far_begin = 0; + float fade_far_end = 0; + float force_alpha = 1.0; + float parent_fade_alpha = 1.0; + //used during setup uint32_t base_flags = 0; Transform3D transform; @@ -593,6 +604,11 @@ protected: virtual void _render_particle_collider_heightfield(RID p_fb, const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, const PagedArray<GeometryInstance *> &p_instances) override; public: + _FORCE_INLINE_ virtual void update_uniform_sets() override { + base_uniform_set_updated = true; + _update_render_base_uniform_set(); + } + virtual GeometryInstance *geometry_instance_create(RID p_base) override; virtual void geometry_instance_set_skeleton(GeometryInstance *p_geometry_instance, RID p_skeleton) override; virtual void geometry_instance_set_material_override(GeometryInstance *p_geometry_instance, RID p_override) override; @@ -601,6 +617,9 @@ public: virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override; virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override; + virtual void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override; + virtual void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) override; + virtual void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) override; virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override; virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override; virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp index a24860996c..768bd1de9d 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp @@ -66,6 +66,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { unshaded = false; uses_vertex = false; + uses_position = false; uses_sss = false; uses_transmittance = false; uses_screen_texture = false; @@ -126,6 +127,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { actions.write_flag_pointers["MODELVIEW_MATRIX"] = &writes_modelview_or_projection; actions.write_flag_pointers["PROJECTION_MATRIX"] = &writes_modelview_or_projection; actions.write_flag_pointers["VERTEX"] = &uses_vertex; + actions.write_flag_pointers["POSITION"] = &uses_position; actions.uniforms = &uniforms; @@ -265,8 +267,26 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { RD::RenderPrimitive primitive_rd = uses_point_size ? RD::RENDER_PRIMITIVE_POINTS : primitive_rd_table[j]; - for (int k = 0; k < SHADER_VERSION_MAX; k++) { - if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(k)) { + for (int k = 0; k < PIPELINE_VERSION_MAX; k++) { + ShaderVersion shader_version; + static const ShaderVersion shader_version_table[PIPELINE_VERSION_MAX] = { + SHADER_VERSION_DEPTH_PASS, + SHADER_VERSION_DEPTH_PASS_DP, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, + SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI, + SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL, + SHADER_VERSION_DEPTH_PASS_WITH_SDF, + SHADER_VERSION_COLOR_PASS, + SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_COLOR_PASS, + SHADER_VERSION_LIGHTMAP_COLOR_PASS, + SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, + SHADER_VERSION_LIGHTMAP_COLOR_PASS, + }; + + shader_version = shader_version_table[k]; + + if (!static_cast<SceneShaderForwardClustered *>(singleton)->shader.is_variant_enabled(shader_version)) { continue; } RD::PipelineRasterizationState raster_state; @@ -277,8 +297,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { RD::PipelineDepthStencilState depth_stencil = depth_stencil_state; RD::PipelineMultisampleState multisample_state; - if (uses_alpha || uses_blend_alpha) { - // only allow these flags to go through if we have some form of msaa + if (k == PIPELINE_VERSION_TRANSPARENT_PASS || k == PIPELINE_VERSION_LIGHTMAP_TRANSPARENT_PASS) { if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE) { multisample_state.enable_alpha_to_coverage = true; } else if (alpha_antialiasing_mode == ALPHA_ANTIALIASING_ALPHA_TO_COVERAGE_AND_TO_ONE) { @@ -286,43 +305,29 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { multisample_state.enable_alpha_to_one = true; } - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { - blend_state = blend_state_blend; - if (depth_draw == DEPTH_DRAW_OPAQUE) { - depth_stencil.enable_depth_write = false; //alpha does not draw depth - } - } else if (uses_depth_pre_pass && (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP || k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS || k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL)) { - if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { - //none, blend state contains nothing - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { - blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way - } else { - blend_state = blend_state_opaque; //writes to normal and roughness in opaque way - } - } else { - pipelines[i][j][k].clear(); - continue; // do not use this version (will error if using it is attempted) + blend_state = blend_state_blend; + + if (depth_draw == DEPTH_DRAW_OPAQUE) { + depth_stencil.enable_depth_write = false; //alpha does not draw depth } + } else if (k == PIPELINE_VERSION_OPAQUE_PASS || k == PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS) { + blend_state = blend_state_opaque; + } else if (k == PIPELINE_VERSION_DEPTH_PASS || k == PIPELINE_VERSION_DEPTH_PASS_DP) { + //none, leave empty + } else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { + blend_state = blend_state_depth_normal_roughness; + } else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI) { + blend_state = blend_state_depth_normal_roughness_giprobe; + } else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL) { + blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way + } else if (k == PIPELINE_VERSION_DEPTH_PASS_WITH_SDF) { + blend_state = RD::PipelineColorBlendState(); //no color targets for SDF } else { - if (k == SHADER_VERSION_COLOR_PASS || k == SHADER_VERSION_LIGHTMAP_COLOR_PASS) { - blend_state = blend_state_opaque; - } else if (k == SHADER_VERSION_DEPTH_PASS || k == SHADER_VERSION_DEPTH_PASS_DP) { - //none, leave empty - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS) { - blend_state = blend_state_depth_normal_roughness; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI) { - blend_state = blend_state_depth_normal_roughness_giprobe; - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_MATERIAL) { - blend_state = RD::PipelineColorBlendState::create_disabled(5); //writes to normal and roughness in opaque way - } else if (k == SHADER_VERSION_DEPTH_PASS_WITH_SDF) { - blend_state = RD::PipelineColorBlendState(); //no color targets for SDF - } else { - //specular write - blend_state = blend_state_opaque_specular; - } + //specular write + blend_state = blend_state_opaque_specular; } - RID shader_variant = shader_singleton->shader.version_get_shader(version, k); + RID shader_variant = shader_singleton->shader.version_get_shader(version, shader_version); pipelines[i][j][k].setup(shader_variant, primitive_rd, raster_state, multisample_state, depth_stencil, blend_state, 0, singleton->default_specialization_constants); } } @@ -331,47 +336,56 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { valid = true; } -void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void SceneShaderForwardClustered::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { if (!p_texture.is_valid()) { - default_texture_params.erase(p_name); + if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { + default_texture_params[p_name].erase(p_index); + + if (default_texture_params[p_name].is_empty()) { + default_texture_params.erase(p_name); + } + } } else { - default_texture_params[p_name] = p_texture; + if (!default_texture_params.has(p_name)) { + default_texture_params[p_name] = Map<int, RID>(); + } + default_texture_params[p_name][p_index] = p_texture; } } void SceneShaderForwardClustered::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { continue; } - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); + if (E.value.texture_order >= 0) { + order[E.value.texture_order + 100000] = E.key; } else { - order[E->get().order] = E->key(); + order[E.value.order] = E.key; } } - for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); - pi.name = E->get(); + for (const KeyValue<int, StringName> &E : order) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); + pi.name = E.value; p_param_list->push_back(pi); } } void SceneShaderForwardClustered::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } RendererStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E->get()); - p.info.name = E->key(); //supply name - p.index = E->get().instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p.info = ShaderLanguage::uniform_to_property_info(E.value); + p.info.name = E.key; //supply name + p.index = E.value.instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -396,7 +410,7 @@ Variant SceneShaderForwardClustered::ShaderData::get_default_parameter(const Str if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } @@ -571,6 +585,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.renames["CUSTOM1"] = "custom1_attrib"; actions.renames["CUSTOM2"] = "custom2_attrib"; actions.renames["CUSTOM3"] = "custom3_attrib"; + actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; // not implemented but need these just in case code is in the shaders actions.renames["VIEW_INDEX"] = "0"; @@ -601,10 +616,10 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.usage_defines["UV2"] = "#define UV2_USED\n"; actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; - actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; - actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; - actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; - actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; + actions.usage_defines["CUSTOM0"] = "#define CUSTOM0_USED\n"; + actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n"; + actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n"; + actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n"; actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; @@ -635,6 +650,7 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n"; + actions.render_mode_defines["depth_draw_opaque"] = "#define USE_OPAQUE_PREPASS\n"; bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); @@ -655,6 +671,10 @@ void SceneShaderForwardClustered::init(RendererStorageRD *p_storage, const Strin actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; } + actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; // linear filter with mipmaps + actions.custom_samplers["DEPTH_TEXTURE"] = "material_samplers[3]"; + actions.custom_samplers["NORMAL_ROUGHNESS_TEXTURE"] = "material_samplers[1]"; // linear filter + actions.render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; actions.render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; actions.render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; diff --git a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h index 8d75f30a20..f2a55939f4 100644 --- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.h @@ -55,10 +55,25 @@ public: SHADER_VERSION_COLOR_PASS_WITH_SEPARATE_SPECULAR, SHADER_VERSION_LIGHTMAP_COLOR_PASS, SHADER_VERSION_LIGHTMAP_COLOR_PASS_WITH_SEPARATE_SPECULAR, - SHADER_VERSION_MAX }; + enum PipelineVersion { + PIPELINE_VERSION_DEPTH_PASS, + PIPELINE_VERSION_DEPTH_PASS_DP, + PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS, + PIPELINE_VERSION_DEPTH_PASS_WITH_NORMAL_AND_ROUGHNESS_AND_VOXEL_GI, + PIPELINE_VERSION_DEPTH_PASS_WITH_MATERIAL, + PIPELINE_VERSION_DEPTH_PASS_WITH_SDF, + PIPELINE_VERSION_OPAQUE_PASS, + PIPELINE_VERSION_OPAQUE_PASS_WITH_SEPARATE_SPECULAR, + PIPELINE_VERSION_TRANSPARENT_PASS, + PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS, + PIPELINE_VERSION_LIGHTMAP_OPAQUE_PASS_WITH_SEPARATE_SPECULAR, + PIPELINE_VERSION_LIGHTMAP_TRANSPARENT_PASS, + PIPELINE_VERSION_MAX + }; + enum ShaderSpecializations { SHADER_SPECIALIZATION_FORWARD_GI = 1 << 0, SHADER_SPECIALIZATION_PROJECTOR = 1 << 1, @@ -109,7 +124,7 @@ public: bool valid; RID version; uint32_t vertex_input_mask; - PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][SHADER_VERSION_MAX]; + PipelineCacheRD pipelines[CULL_VARIANT_MAX][RS::PRIMITIVE_MAX][PIPELINE_VERSION_MAX]; String path; @@ -120,7 +135,7 @@ public: uint32_t ubo_size; String code; - Map<StringName, RID> default_texture_params; + Map<StringName, Map<int, RID>> default_texture_params; DepthDraw depth_draw; DepthTest depth_test; @@ -137,6 +152,7 @@ public: bool unshaded; bool uses_vertex; + bool uses_position; bool uses_sss; bool uses_transmittance; bool uses_screen_texture; @@ -150,7 +166,7 @@ public: uint32_t index = 0; virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp index 276a44bc27..445623fb86 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -159,7 +159,6 @@ void RenderForwardMobile::RenderBufferDataForwardMobile::configure(RID p_color_b RD::TEXTURE_SAMPLES_2, RD::TEXTURE_SAMPLES_4, RD::TEXTURE_SAMPLES_8, - RD::TEXTURE_SAMPLES_16 }; texture_samples = ts[p_msaa]; @@ -484,6 +483,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color scene_state.ubo.viewport_size[0] = vp_he.x; scene_state.ubo.viewport_size[1] = vp_he.y; scene_state.ubo.directional_light_count = 0; + scene_state.ubo.opaque_prepass_threshold = 0.0; // We can only use our full subpass approach if we're: // - not reading from SCREEN_TEXTURE/DEPTH_TEXTURE @@ -794,7 +794,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (using_subpass_transparent) { RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); - RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); + RenderListParameters render_list_params(render_list[RENDER_LIST_ALPHA].elements.ptr(), render_list[RENDER_LIST_ALPHA].element_info.ptr(), render_list[RENDER_LIST_ALPHA].elements.size(), reverse_cull, PASS_MODE_COLOR_TRANSPARENT, rp_uniform_set, spec_constant_base_flags, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->lod_camera_plane, p_render_data->lod_distance_multiplier, p_render_data->screen_lod_threshold, p_render_data->view_count); render_list_params.framebuffer_format = fb_format; if ((uint32_t)render_list_params.element_count > render_list_thread_threshold && false) { // secondary command buffers need more testing at this time @@ -898,6 +898,7 @@ void RenderForwardMobile::_render_shadow_append(RID p_framebuffer, const PagedAr render_data.lod_distance_multiplier = p_lod_distance_multiplier; scene_state.ubo.dual_paraboloid_side = p_use_dp_flip ? -1 : 1; + scene_state.ubo.opaque_prepass_threshold = 0.1; _setup_environment(&render_data, true, Vector2(1, 1), !p_flip_y, Color(), false, p_use_pancake, shadow_pass_index); @@ -979,6 +980,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c scene_state.ubo.dual_paraboloid_side = 0; scene_state.ubo.material_uv2_mode = false; + scene_state.ubo.opaque_prepass_threshold = 0.0f; RenderDataRD render_data; render_data.cam_projection = p_cam_projection; @@ -1090,6 +1092,7 @@ void RenderForwardMobile::_render_particle_collider_heightfield(RID p_fb, const _update_render_base_uniform_set(); scene_state.ubo.dual_paraboloid_side = 0; + scene_state.ubo.opaque_prepass_threshold = 0.0; RenderDataRD render_data; render_data.cam_projection = p_cam_projection; @@ -1323,7 +1326,7 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const } uint32_t lightmap_captures_used = 0; - Plane near_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z)); + Plane near_plane(-p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z), p_render_data->cam_transform.origin); near_plane.d += p_render_data->cam_projection.get_z_near(); float z_max = p_render_data->cam_projection.get_z_far() - p_render_data->cam_projection.get_z_near(); @@ -1448,13 +1451,13 @@ void RenderForwardMobile::_fill_render_list(RenderListType p_render_list, const } // ADD Element - if (p_pass_mode == PASS_MODE_COLOR) { + if (p_pass_mode == PASS_MODE_COLOR || p_pass_mode == PASS_MODE_COLOR_TRANSPARENT) { #ifdef DEBUG_ENABLED bool force_alpha = unlikely(get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW); #else bool force_alpha = false; #endif - if (!force_alpha && (surf->flags & (GeometryInstanceSurfaceDataCache::FLAG_PASS_DEPTH | GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE))) { + if (!force_alpha && (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_OPAQUE)) { rl->add_element(surf); } if (force_alpha || (surf->flags & GeometryInstanceSurfaceDataCache::FLAG_PASS_ALPHA)) { @@ -1634,19 +1637,10 @@ void RenderForwardMobile::_setup_environment(const RenderDataRD *p_render_data, scene_state.ubo.ssao_ao_affect = environment_get_ssao_ao_affect(p_render_data->environment); scene_state.ubo.ssao_light_affect = environment_get_ssao_light_affect(p_render_data->environment); - Color ao_color = environment_get_ao_color(p_render_data->environment).to_linear(); - scene_state.ubo.ao_color[0] = ao_color.r; - scene_state.ubo.ao_color[1] = ao_color.g; - scene_state.ubo.ao_color[2] = ao_color.b; - scene_state.ubo.ao_color[3] = ao_color.a; - scene_state.ubo.fog_enabled = environment_is_fog_enabled(p_render_data->environment); scene_state.ubo.fog_density = environment_get_fog_density(p_render_data->environment); scene_state.ubo.fog_height = environment_get_fog_height(p_render_data->environment); scene_state.ubo.fog_height_density = environment_get_fog_height_density(p_render_data->environment); - if (scene_state.ubo.fog_height_density >= 0.0001) { - scene_state.ubo.fog_height_density = 1.0 / scene_state.ubo.fog_height_density; - } scene_state.ubo.fog_aerial_perspective = environment_get_fog_aerial_perspective(p_render_data->environment); Color fog_color = environment_get_fog_light_color(p_render_data->environment).to_linear(); @@ -1831,6 +1825,10 @@ void RenderForwardMobile::_render_list_template(RenderingDevice::DrawListID p_dr const RenderElementInfo &element_info = p_params->element_info[i]; const GeometryInstanceForwardMobile *inst = surf->owner; + if (inst->instance_count == 0) { + continue; + } + uint32_t base_spec_constants = p_params->spec_constant_base_flags; // GeometryInstanceForwardMobile::PushConstant push_constant = inst->push_constant; @@ -2082,6 +2080,15 @@ void RenderForwardMobile::geometry_instance_set_lod_bias(GeometryInstance *p_geo ginstance->lod_bias = p_lod_bias; } +void RenderForwardMobile::geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) { +} + +void RenderForwardMobile::geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) { +} + +void RenderForwardMobile::geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) { +} + void RenderForwardMobile::geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) { GeometryInstanceForwardMobile *ginstance = static_cast<GeometryInstanceForwardMobile *>(p_geometry_instance); ERR_FAIL_COND(!ginstance); @@ -2441,7 +2448,7 @@ void RenderForwardMobile::_geometry_instance_update(GeometryInstance *p_geometry } break; #if 0 case RS::INSTANCE_IMMEDIATE: { - RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getornull(inst->base); + RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.get_or_null(inst->base); ERR_CONTINUE(!immediate); _add_geometry(immediate, inst, nullptr, -1, p_depth_pass, p_shadow_pass); diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h index 38f80c5347..485d08b589 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -292,9 +292,8 @@ protected: float roughness_limiter_amount; float roughness_limiter_limit; - uint32_t roughness_limiter_pad[2]; - - float ao_color[4]; + float opaque_prepass_threshold; + uint32_t roughness_limiter_pad; // Fog uint32_t fog_enabled; @@ -634,6 +633,9 @@ public: virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabb) override; virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) override; virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) override; + virtual void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) override; + virtual void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) override; + virtual void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) override; virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) override; virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) override; virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) override; diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp index 14b3b6d9aa..e6d9a60f94 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp @@ -325,47 +325,56 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { valid = true; } -void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void SceneShaderForwardMobile::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { if (!p_texture.is_valid()) { - default_texture_params.erase(p_name); + if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { + default_texture_params[p_name].erase(p_index); + + if (default_texture_params[p_name].is_empty()) { + default_texture_params.erase(p_name); + } + } } else { - default_texture_params[p_name] = p_texture; + if (!default_texture_params.has(p_name)) { + default_texture_params[p_name] = Map<int, RID>(); + } + default_texture_params[p_name][p_index] = p_texture; } } void SceneShaderForwardMobile::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { continue; } - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); + if (E.value.texture_order >= 0) { + order[E.value.texture_order + 100000] = E.key; } else { - order[E->get().order] = E->key(); + order[E.value.order] = E.key; } } - for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); - pi.name = E->get(); + for (const KeyValue<int, StringName> &E : order) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); + pi.name = E.value; p_param_list->push_back(pi); } } void SceneShaderForwardMobile::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } RendererStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E->get()); - p.info.name = E->key(); //supply name - p.index = E->get().instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p.info = ShaderLanguage::uniform_to_property_info(E.value); + p.info.name = E.key; //supply name + p.index = E.value.instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -390,7 +399,7 @@ Variant SceneShaderForwardMobile::ShaderData::get_default_parameter(const String if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } @@ -564,6 +573,7 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.renames["CUSTOM1"] = "custom1_attrib"; actions.renames["CUSTOM2"] = "custom2_attrib"; actions.renames["CUSTOM3"] = "custom3_attrib"; + actions.renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; actions.renames["VIEW_INDEX"] = "ViewIndex"; actions.renames["VIEW_MONO_LEFT"] = "0"; @@ -593,10 +603,10 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.usage_defines["UV2"] = "#define UV2_USED\n"; actions.usage_defines["BONE_INDICES"] = "#define BONES_USED\n"; actions.usage_defines["BONE_WEIGHTS"] = "#define WEIGHTS_USED\n"; - actions.usage_defines["CUSTOM0"] = "#define CUSTOM0\n"; - actions.usage_defines["CUSTOM1"] = "#define CUSTOM1\n"; - actions.usage_defines["CUSTOM2"] = "#define CUSTOM2\n"; - actions.usage_defines["CUSTOM3"] = "#define CUSTOM3\n"; + actions.usage_defines["CUSTOM0"] = "#define CUSTOM0_USED\n"; + actions.usage_defines["CUSTOM1"] = "#define CUSTOM1_USED\n"; + actions.usage_defines["CUSTOM2"] = "#define CUSTOM2_USED\n"; + actions.usage_defines["CUSTOM3"] = "#define CUSTOM3_USED\n"; actions.usage_defines["NORMAL_MAP"] = "#define NORMAL_MAP_USED\n"; actions.usage_defines["NORMAL_MAP_DEPTH"] = "@NORMAL_MAP"; actions.usage_defines["COLOR"] = "#define COLOR_USED\n"; @@ -627,6 +637,7 @@ void SceneShaderForwardMobile::init(RendererStorageRD *p_storage, const String p actions.render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; actions.render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; actions.render_mode_defines["particle_trails"] = "#define USE_PARTICLE_TRAILS\n"; + actions.render_mode_defines["depth_draw_opaque"] = "#define USE_OPAQUE_PREPASS\n"; bool force_lambert = GLOBAL_GET("rendering/shading/overrides/force_lambert_over_burley"); if (!force_lambert) { diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h index e1c10f0206..392fac1e3e 100644 --- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h @@ -111,7 +111,7 @@ public: uint32_t ubo_size; String code; - Map<StringName, RID> default_texture_params; + Map<StringName, Map<int, RID>> default_texture_params; DepthDraw depth_draw; DepthTest depth_test; @@ -141,7 +141,7 @@ public: uint32_t index = 0; virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; diff --git a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp index aefe926cb0..0d60052666 100644 --- a/servers/rendering/renderer_rd/pipeline_cache_rd.cpp +++ b/servers/rendering/renderer_rd/pipeline_cache_rd.cpp @@ -35,8 +35,10 @@ RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD RD::PipelineMultisampleState multisample_state_version = multisample_state; multisample_state_version.sample_count = RD::get_singleton()->framebuffer_format_get_texture_samples(p_framebuffer_format_id, p_render_pass); + bool wireframe = p_wireframe || rasterization_state.wireframe; + RD::PipelineRasterizationState raster_state_version = rasterization_state; - raster_state_version.wireframe = p_wireframe; + raster_state_version.wireframe = wireframe; Vector<RD::PipelineSpecializationConstant> specialization_constants = base_specialization_constants; @@ -59,7 +61,7 @@ RID PipelineCacheRD::_generate_version(RD::VertexFormatID p_vertex_format_id, RD versions = (Version *)memrealloc(versions, sizeof(Version) * (version_count + 1)); versions[version_count].framebuffer_id = p_framebuffer_format_id; versions[version_count].vertex_id = p_vertex_format_id; - versions[version_count].wireframe = p_wireframe; + versions[version_count].wireframe = wireframe; versions[version_count].pipeline = pipeline; versions[version_count].render_pass = p_render_pass; versions[version_count].bool_specializations = p_bool_specializations; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 647c348d9f..d013099cce 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "renderer_canvas_render_rd.h" + #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" #include "core/math/math_defs.h" @@ -757,6 +758,10 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend instance_count = storage->multimesh_get_instances_to_draw(multimesh); + if (instance_count == 0) { + break; + } + RID uniform_set = storage->multimesh_get_2d_uniform_set(multimesh, shader.default_version_rd_shader, TRANSFORMS_UNIFORM_SET); RD::get_singleton()->draw_list_bind_uniform_set(p_draw_list, uniform_set, TRANSFORMS_UNIFORM_SET); push_constant.flags |= 1; //multimesh, trails disabled @@ -1086,7 +1091,7 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co } } - RID material = ci->material; + RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material; if (material.is_null() && ci->canvas_group != nullptr) { material = default_canvas_group_material; @@ -1144,7 +1149,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p continue; } - CanvasLight *clight = canvas_light_owner.getornull(l->light_internal); + CanvasLight *clight = canvas_light_owner.get_or_null(l->light_internal); if (!clight) { //unused or invalid texture l->render_index_cache = -1; l = l->next_ptr; @@ -1207,7 +1212,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p continue; } - CanvasLight *clight = canvas_light_owner.getornull(l->light_internal); + CanvasLight *clight = canvas_light_owner.get_or_null(l->light_internal); if (!clight) { //unused or invalid texture l->render_index_cache = -1; l = l->next_ptr; @@ -1354,8 +1359,10 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p } } - if (ci->material.is_valid()) { - MaterialData *md = (MaterialData *)storage->material_get_data(ci->material, RendererStorageRD::SHADER_TYPE_2D); + RID material = ci->material_owner == nullptr ? ci->material : ci->material_owner->material; + + if (material.is_valid()) { + MaterialData *md = (MaterialData *)storage->material_get_data(material, RendererStorageRD::SHADER_TYPE_2D); if (md && md->shader_data->valid) { if (md->shader_data->uses_screen_texture && canvas_group_owner == nullptr) { if (!material_screen_texture_found) { @@ -1375,7 +1382,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p if (!RD::get_singleton()->uniform_set_is_valid(md->uniform_set)) { // uniform set may be gone because a dependency was erased. In this case, it will happen // if a texture is deleted, so just re-create it. - storage->material_force_update_textures(ci->material, RendererStorageRD::SHADER_TYPE_2D); + storage->material_force_update_textures(material, RendererStorageRD::SHADER_TYPE_2D); } } } @@ -1392,6 +1399,7 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p update_skeletons = true; } } + c = c->next; } } @@ -1478,7 +1486,7 @@ RID RendererCanvasRenderRD::light_create() { } void RendererCanvasRenderRD::light_set_texture(RID p_rid, RID p_texture) { - CanvasLight *cl = canvas_light_owner.getornull(p_rid); + CanvasLight *cl = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_COND(!cl); if (cl->texture == p_texture) { return; @@ -1494,7 +1502,7 @@ void RendererCanvasRenderRD::light_set_texture(RID p_rid, RID p_texture) { } void RendererCanvasRenderRD::light_set_use_shadow(RID p_rid, bool p_enable) { - CanvasLight *cl = canvas_light_owner.getornull(p_rid); + CanvasLight *cl = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_COND(!cl); cl->shadow.enabled = p_enable; @@ -1534,7 +1542,7 @@ void RendererCanvasRenderRD::_update_shadow_atlas() { } } void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders) { - CanvasLight *cl = canvas_light_owner.getornull(p_rid); + CanvasLight *cl = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_COND(!cl->shadow.enabled); _update_shadow_atlas(); @@ -1582,13 +1590,10 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, push_constant.z_far = p_far; push_constant.pad = 0; - /*if (i == 0) - *p_xform_cache = projection;*/ - LightOccluderInstance *instance = p_occluders; while (instance) { - OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder); if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) { instance = instance->next; @@ -1612,14 +1617,14 @@ void RendererCanvasRenderRD::light_update_shadow(RID p_rid, int p_shadow_index, } void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_shadow_index, const Transform2D &p_light_xform, int p_light_mask, float p_cull_distance, const Rect2 &p_clip_rect, LightOccluderInstance *p_occluders) { - CanvasLight *cl = canvas_light_owner.getornull(p_rid); + CanvasLight *cl = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_COND(!cl->shadow.enabled); _update_shadow_atlas(); Vector2 light_dir = p_light_xform.elements[1].normalized(); - Vector2 center = p_clip_rect.position + p_clip_rect.size * 0.5; + Vector2 center = p_clip_rect.get_center(); float to_edge_distance = ABS(light_dir.dot(p_clip_rect.get_support(light_dir)) - light_dir.dot(center)); @@ -1663,7 +1668,7 @@ void RendererCanvasRenderRD::light_update_directional_shadow(RID p_rid, int p_sh LightOccluderInstance *instance = p_occluders; while (instance) { - OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder); if (!co || co->index_array.is_null() || !(p_light_mask & instance->light_mask)) { instance = instance->next; @@ -1729,7 +1734,7 @@ void RendererCanvasRenderRD::render_sdf(RID p_render_target, LightOccluderInstan LightOccluderInstance *instance = p_occluders; while (instance) { - OccluderPolygon *co = occluder_polygon_owner.getornull(instance->occluder); + OccluderPolygon *co = occluder_polygon_owner.get_or_null(instance->occluder); if (!co || co->sdf_index_array.is_null()) { instance = instance->next; @@ -1763,7 +1768,7 @@ RID RendererCanvasRenderRD::occluder_polygon_create() { } void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) { - OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); + OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder); ERR_FAIL_COND(!oc); Vector<Vector2> lines; @@ -1932,7 +1937,7 @@ void RendererCanvasRenderRD::occluder_polygon_set_shape(RID p_occluder, const Ve } void RendererCanvasRenderRD::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) { - OccluderPolygon *oc = occluder_polygon_owner.getornull(p_occluder); + OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder); ERR_FAIL_COND(!oc); oc->cull_mode = p_mode; } @@ -2119,46 +2124,55 @@ void RendererCanvasRenderRD::ShaderData::set_code(const String &p_code) { valid = true; } -void RendererCanvasRenderRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererCanvasRenderRD::ShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { if (!p_texture.is_valid()) { - default_texture_params.erase(p_name); + if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { + default_texture_params[p_name].erase(p_index); + + if (default_texture_params[p_name].is_empty()) { + default_texture_params.erase(p_name); + } + } } else { - default_texture_params[p_name] = p_texture; + if (!default_texture_params.has(p_name)) { + default_texture_params[p_name] = Map<int, RID>(); + } + default_texture_params[p_name][p_index] = p_texture; } } void RendererCanvasRenderRD::ShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_LOCAL) { continue; } - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); + if (E.value.texture_order >= 0) { + order[E.value.texture_order + 100000] = E.key; } else { - order[E->get().order] = E->key(); + order[E.value.order] = E.key; } } - for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); - pi.name = E->get(); + for (const KeyValue<int, StringName> &E : order) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); + pi.name = E.value; p_param_list->push_back(pi); } } void RendererCanvasRenderRD::ShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } RendererStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E->get()); - p.info.name = E->key(); //supply name - p.index = E->get().instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p.info = ShaderLanguage::uniform_to_property_info(E.value); + p.info.name = E.key; //supply name + p.index = E.value.instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -2183,7 +2197,7 @@ Variant RendererCanvasRenderRD::ShaderData::get_default_parameter(const StringNa if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } @@ -2608,7 +2622,7 @@ void fragment() { bool RendererCanvasRenderRD::free(RID p_rid) { if (canvas_light_owner.owns(p_rid)) { - CanvasLight *cl = canvas_light_owner.getornull(p_rid); + CanvasLight *cl = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_COND_V(!cl, false); light_set_use_shadow(p_rid, false); canvas_light_owner.free(p_rid); diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index ec7d7e2854..26ccbd3bf5 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -173,14 +173,14 @@ class RendererCanvasRenderRD : public RendererCanvasRender { uint32_t ubo_size; String code; - Map<StringName, RID> default_texture_params; + Map<StringName, Map<int, RID>> default_texture_params; bool uses_screen_texture = false; bool uses_sdf = false; bool uses_time = false; virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp index 62e9386f95..522a8e8112 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.cpp @@ -46,6 +46,8 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID RID rd_texture = storage->texture_get_rd_texture(texture); ERR_CONTINUE(rd_texture.is_null()); + // TODO if keep_3d_linear was set when rendering to this render target we need to add a linear->sRGB conversion in. + if (!render_target_descriptors.has(rd_texture) || !RD::get_singleton()->uniform_set_is_valid(render_target_descriptors[rd_texture])) { Vector<RD::Uniform> uniforms; RD::Uniform u; @@ -65,10 +67,14 @@ void RendererCompositorRD::blit_render_targets_to_screen(DisplayServer::WindowID RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, render_target_descriptors[rd_texture], 0); - blit.push_constant.rect[0] = p_render_targets[i].rect.position.x / screen_size.width; - blit.push_constant.rect[1] = p_render_targets[i].rect.position.y / screen_size.height; - blit.push_constant.rect[2] = p_render_targets[i].rect.size.width / screen_size.width; - blit.push_constant.rect[3] = p_render_targets[i].rect.size.height / screen_size.height; + blit.push_constant.src_rect[0] = p_render_targets[i].src_rect.position.x; + blit.push_constant.src_rect[1] = p_render_targets[i].src_rect.position.y; + blit.push_constant.src_rect[2] = p_render_targets[i].src_rect.size.width; + blit.push_constant.src_rect[3] = p_render_targets[i].src_rect.size.height; + blit.push_constant.dst_rect[0] = p_render_targets[i].dst_rect.position.x / screen_size.width; + blit.push_constant.dst_rect[1] = p_render_targets[i].dst_rect.position.y / screen_size.height; + blit.push_constant.dst_rect[2] = p_render_targets[i].dst_rect.size.width / screen_size.width; + blit.push_constant.dst_rect[3] = p_render_targets[i].dst_rect.size.height / screen_size.height; blit.push_constant.layer = p_render_targets[i].multi_view.layer; blit.push_constant.eye_center[0] = p_render_targets[i].lens_distortion.eye_center.x; blit.push_constant.eye_center[1] = p_render_targets[i].lens_distortion.eye_center.y; @@ -191,7 +197,7 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color } } else { screenrect = imgrect; - screenrect.position += ((Size2(window_size.width, window_size.height) - screenrect.size) / 2.0).floor(); + screenrect.position += ((window_size - screenrect.size) / 2.0).floor(); } screenrect.position /= window_size; @@ -203,10 +209,14 @@ void RendererCompositorRD::set_boot_image(const Ref<Image> &p_image, const Color RD::get_singleton()->draw_list_bind_index_array(draw_list, blit.array); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uset, 0); - blit.push_constant.rect[0] = screenrect.position.x; - blit.push_constant.rect[1] = screenrect.position.y; - blit.push_constant.rect[2] = screenrect.size.width; - blit.push_constant.rect[3] = screenrect.size.height; + blit.push_constant.src_rect[0] = 0.0; + blit.push_constant.src_rect[1] = 0.0; + blit.push_constant.src_rect[2] = 1.0; + blit.push_constant.src_rect[3] = 1.0; + blit.push_constant.dst_rect[0] = screenrect.position.x; + blit.push_constant.dst_rect[1] = screenrect.position.y; + blit.push_constant.dst_rect[2] = screenrect.size.width; + blit.push_constant.dst_rect[3] = screenrect.size.height; blit.push_constant.layer = 0; blit.push_constant.eye_center[0] = 0; blit.push_constant.eye_center[1] = 0; @@ -271,12 +281,12 @@ RendererCompositorRD::RendererCompositorRD() { storage = memnew(RendererStorageRD); canvas = memnew(RendererCanvasRenderRD(storage)); - uint32_t back_end = GLOBAL_GET("rendering/vulkan/rendering/back_end"); + back_end = (bool)(int)GLOBAL_GET("rendering/vulkan/rendering/back_end"); uint32_t textures_per_stage = RD::get_singleton()->limit_get(RD::LIMIT_MAX_TEXTURES_PER_SHADER_STAGE); - if (back_end == 1 || textures_per_stage < 48) { + if (back_end || textures_per_stage < 48) { scene = memnew(RendererSceneRenderImplementation::RenderForwardMobile(storage)); - } else { // back_end == 0 + } else { // back_end == false // default to our high end renderer scene = memnew(RendererSceneRenderImplementation::RenderForwardClustered(storage)); } diff --git a/servers/rendering/renderer_rd/renderer_compositor_rd.h b/servers/rendering/renderer_rd/renderer_compositor_rd.h index 8639362da9..f69e40e0ff 100644 --- a/servers/rendering/renderer_rd/renderer_compositor_rd.h +++ b/servers/rendering/renderer_rd/renderer_compositor_rd.h @@ -55,7 +55,8 @@ protected: }; struct BlitPushConstant { - float rect[4]; + float src_rect[4]; + float dst_rect[4]; float eye_center[2]; float k1; @@ -115,8 +116,6 @@ public: _create_func = _create_current; } - virtual bool is_low_end() const { return false; } - static RendererCompositorRD *singleton; RendererCompositorRD(); ~RendererCompositorRD(); diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp index d631cb4bac..550e59ba98 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.cpp @@ -32,13 +32,12 @@ uint64_t RendererSceneEnvironmentRD::auto_exposure_counter = 2; -void RendererSceneEnvironmentRD::set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) { +void RendererSceneEnvironmentRD::set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source) { ambient_light = p_color; ambient_source = p_ambient; ambient_light_energy = p_energy; ambient_sky_contribution = p_sky_contribution; reflection_source = p_reflection_source; - ao_color = p_ao_color; } void RendererSceneEnvironmentRD::set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { @@ -93,16 +92,19 @@ void RendererSceneEnvironmentRD::set_fog(bool p_enable, const Color &p_light_col fog_aerial_perspective = p_fog_aerial_perspective; } -void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) { +void RendererSceneEnvironmentRD::set_volumetric_fog(bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) { volumetric_fog_enabled = p_enable; volumetric_fog_density = p_density; - volumetric_fog_light = p_light; - volumetric_fog_light_energy = p_light_energy; + volumetric_fog_scattering = p_albedo; + volumetric_fog_emission = p_emission; + volumetric_fog_emission_energy = p_emission_energy; + volumetric_fog_anisotropy = p_anisotropy, volumetric_fog_length = p_length; volumetric_fog_detail_spread = p_detail_spread; volumetric_fog_gi_inject = p_gi_inject; volumetric_fog_temporal_reprojection = p_temporal_reprojection; volumetric_fog_temporal_reprojection_amount = p_temporal_reprojection_amount; + volumetric_fog_ambient_inject = p_ambient_inject; } void RendererSceneEnvironmentRD::set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { diff --git a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h index 992c4bf471..ec9cb4a798 100644 --- a/servers/rendering/renderer_rd/renderer_scene_environment_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_environment_rd.h @@ -52,7 +52,6 @@ public: float ambient_light_energy = 1.0; float ambient_sky_contribution = 1.0; RS::EnvironmentReflectionSource reflection_source = RS::ENV_REFLECTION_SOURCE_BG; - Color ao_color; /// Tonemap @@ -80,13 +79,16 @@ public: /// bool volumetric_fog_enabled = false; float volumetric_fog_density = 0.01; - Color volumetric_fog_light = Color(0, 0, 0); - float volumetric_fog_light_energy = 0.0; + Color volumetric_fog_scattering = Color(1, 1, 1); + Color volumetric_fog_emission = Color(0, 0, 0); + float volumetric_fog_emission_energy = 0.0; + float volumetric_fog_anisotropy = 0.2; float volumetric_fog_length = 64.0; float volumetric_fog_detail_spread = 2.0; float volumetric_fog_gi_inject = 0.0; bool volumetric_fog_temporal_reprojection = true; float volumetric_fog_temporal_reprojection_amount = 0.9; + float volumetric_fog_ambient_inject = 0.0; /// Glow @@ -142,12 +144,12 @@ public: bool use_1d_color_correction = false; RID color_correction = RID(); - void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color); + void set_ambient_light(const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source); void set_tonemap(RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); void set_glow(bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap); void set_sdfgi(bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias); void set_fog(bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective); - void set_volumetric_fog(bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount); + void set_volumetric_fog(bool p_enable, float p_density, const Color &p_scatterin, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject); void set_ssr(bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance); void set_ssao(bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect); }; diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp index 098e2a5c87..b6b5c90b39 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.cpp @@ -1450,7 +1450,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re break; } - RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j)); + RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->directional_lights->get(j)); ERR_CONTINUE(!li); if (storage->light_directional_is_sky_only(li->light)) { @@ -1469,7 +1469,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re lights[idx].color[1] = color.g; lights[idx].color[2] = color.b; lights[idx].type = RS::LIGHT_DIRECTIONAL; - lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); + lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY); lights[idx].has_shadow = storage->light_has_shadow(li->light); idx++; @@ -1484,7 +1484,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re break; } - RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]); + RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_scene_render->render_state.sdfgi_update_data->positional_light_instances[j]); ERR_CONTINUE(!li); uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); @@ -1514,7 +1514,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re lights[idx].color[1] = color.g; lights[idx].color[2] = color.b; lights[idx].type = storage->light_get_type(li->light); - lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); + lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY); lights[idx].has_shadow = storage->light_has_shadow(li->light); lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); @@ -1534,7 +1534,7 @@ void RendererSceneGIRD::SDFGI::pre_process_gi(const Transform3D &p_transform, Re void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, const PagedArray<RendererSceneRender::GeometryInstance *> &p_instances, RendererSceneRenderRD *p_scene_render) { //print_line("rendering region " + itos(p_region)); - RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); + RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but... AABB bounds; Vector3i from; @@ -1892,7 +1892,7 @@ void RendererSceneGIRD::SDFGI::render_region(RID p_render_buffers, int p_region, } void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32_t p_cascade_count, const uint32_t *p_cascade_indices, const PagedArray<RID> *p_positional_light_cull_result, RendererSceneRenderRD *p_scene_render) { - RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); + RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); // we wouldn't be here if this failed but... RD::get_singleton()->draw_command_begin_label("SDFGI Render Static Lighs"); @@ -1921,7 +1921,7 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32 break; } - RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.getornull(p_positional_light_cull_result[i][j]); + RendererSceneRenderRD::LightInstance *li = p_scene_render->light_instance_owner.get_or_null(p_positional_light_cull_result[i][j]); ERR_CONTINUE(!li); uint32_t max_sdfgi_cascade = storage->light_get_max_sdfgi_cascade(li->light); @@ -1953,7 +1953,7 @@ void RendererSceneGIRD::SDFGI::render_static_lights(RID p_render_buffers, uint32 lights[idx].color[0] = color.r; lights[idx].color[1] = color.g; lights[idx].color[2] = color.b; - lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY); + lights[idx].energy = storage->light_get_param(li->light, RS::LIGHT_PARAM_ENERGY) * storage->light_get_param(li->light, RS::LIGHT_PARAM_INDIRECT_ENERGY); lights[idx].has_shadow = storage->light_has_shadow(li->light); lights[idx].attenuation = storage->light_get_param(li->light, RS::LIGHT_PARAM_ATTENUATION); lights[idx].radius = storage->light_get_param(li->light, RS::LIGHT_PARAM_RANGE); @@ -2575,7 +2575,7 @@ void RendererSceneGIRD::VoxelGIInstance::update(bool p_update_light_instances, c Vector3 render_dir = render_z[j]; Vector3 up_dir = render_up[j]; - Vector3 center = aabb.position + aabb.size * 0.5; + Vector3 center = aabb.get_center(); Transform3D xform; xform.set_look_at(center - aabb.size * 0.5 * render_dir, center, up_dir); @@ -3024,7 +3024,7 @@ void RendererSceneGIRD::setup_voxel_gi_instances(RID p_render_buffers, const Tra r_voxel_gi_instances_used = 0; // feels a little dirty to use our container this way but.... - RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); + RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(rb == nullptr); RID voxel_gi_buffer = p_scene_render->render_buffers_get_voxel_gi_buffer(p_render_buffers); @@ -3098,12 +3098,14 @@ void RendererSceneGIRD::setup_voxel_gi_instances(RID p_render_buffers, const Tra } rb->gi.uniform_set = RID(); if (rb->volumetric_fog) { - if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { - RD::get_singleton()->free(rb->volumetric_fog->uniform_set); - RD::get_singleton()->free(rb->volumetric_fog->uniform_set2); + if (RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) { + RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set); + RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set); + RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set2); } - rb->volumetric_fog->uniform_set = RID(); - rb->volumetric_fog->uniform_set2 = RID(); + rb->volumetric_fog->fog_uniform_set = RID(); + rb->volumetric_fog->process_uniform_set = RID(); + rb->volumetric_fog->process_uniform_set2 = RID(); } } @@ -3119,9 +3121,8 @@ void RendererSceneGIRD::setup_voxel_gi_instances(RID p_render_buffers, const Tra void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_buffer, RID p_voxel_gi_buffer, RID p_environment, const CameraMatrix &p_projection, const Transform3D &p_transform, const PagedArray<RID> &p_voxel_gi_instances, RendererSceneRenderRD *p_scene_render) { RD::get_singleton()->draw_command_begin_label("GI Render"); - RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.getornull(p_render_buffers); + RendererSceneRenderRD::RenderBuffers *rb = p_scene_render->render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(rb == nullptr); - RendererSceneEnvironmentRD *env = p_scene_render->environment_owner.getornull(p_environment); if (rb->ambient_buffer.is_null() || rb->gi.using_half_size_gi != half_resolution) { if (rb->ambient_buffer.is_valid()) { @@ -3131,8 +3132,8 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; if (half_resolution) { tf.width >>= 1; tf.height >>= 1; @@ -3145,13 +3146,13 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ PushConstant push_constant; - push_constant.screen_size[0] = rb->width; - push_constant.screen_size[1] = rb->height; + push_constant.screen_size[0] = rb->internal_width; + push_constant.screen_size[1] = rb->internal_height; push_constant.z_near = p_projection.get_z_near(); push_constant.z_far = p_projection.get_z_far(); push_constant.orthogonal = p_projection.is_orthogonal(); - push_constant.proj_info[0] = -2.0f / (rb->width * p_projection.matrix[0][0]); - push_constant.proj_info[1] = -2.0f / (rb->height * p_projection.matrix[1][1]); + push_constant.proj_info[0] = -2.0f / (rb->internal_width * p_projection.matrix[0][0]); + push_constant.proj_info[1] = -2.0f / (rb->internal_height * p_projection.matrix[1][1]); push_constant.proj_info[2] = (1.0f - p_projection.matrix[0][2]) / p_projection.matrix[0][0]; push_constant.proj_info[3] = (1.0f + p_projection.matrix[1][2]) / p_projection.matrix[1][1]; push_constant.max_voxel_gi_instances = MIN((uint64_t)MAX_VOXEL_GI_INSTANCES, p_voxel_gi_instances.size()); @@ -3160,16 +3161,6 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ bool use_sdfgi = rb->sdfgi != nullptr; bool use_voxel_gi_instances = push_constant.max_voxel_gi_instances > 0; - if (env) { - push_constant.ao_color[0] = env->ao_color.r; - push_constant.ao_color[1] = env->ao_color.g; - push_constant.ao_color[2] = env->ao_color.b; - } else { - push_constant.ao_color[0] = 0; - push_constant.ao_color[1] = 0; - push_constant.ao_color[2] = 0; - } - push_constant.cam_rotation[0] = p_transform.basis[0][0]; push_constant.cam_rotation[1] = p_transform.basis[1][0]; push_constant.cam_rotation[2] = p_transform.basis[2][0]; @@ -3353,9 +3344,9 @@ void RendererSceneGIRD::process_gi(RID p_render_buffers, RID p_normal_roughness_ RD::get_singleton()->compute_list_set_push_constant(compute_list, &push_constant, sizeof(PushConstant)); if (rb->gi.using_half_size_gi) { - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width >> 1, rb->height >> 1, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width >> 1, rb->internal_height >> 1, 1); } else { - RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->width, rb->height, 1); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->internal_width, rb->internal_height, 1); } //do barrier later to allow oeverlap //RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_NO_BARRIER); //no barriers, let other compute, raster and transfer happen at the same time @@ -3393,7 +3384,7 @@ void RendererSceneGIRD::voxel_gi_update(RID p_probe, bool p_update_light_instanc } void RendererSceneGIRD::debug_voxel_gi(RID p_voxel_gi, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform, bool p_lighting, bool p_emission, float p_alpha) { - VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.getornull(p_voxel_gi); + VoxelGIInstance *voxel_gi = voxel_gi_instance_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->debug(p_draw_list, p_framebuffer, p_camera_with_transform, p_lighting, p_emission, p_alpha); diff --git a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h index 0b4622646f..9f6fc8a9b7 100644 --- a/servers/rendering/renderer_rd/renderer_scene_gi_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_gi_rd.h @@ -383,7 +383,7 @@ public: mutable RID_Owner<VoxelGIInstance> voxel_gi_instance_owner; _FORCE_INLINE_ VoxelGIInstance *get_probe_instance(RID p_probe) const { - return voxel_gi_instance_owner.getornull(p_probe); + return voxel_gi_instance_owner.get_or_null(p_probe); }; _FORCE_INLINE_ RID voxel_gi_instance_get_texture(RID p_probe) { @@ -623,12 +623,11 @@ public: float z_far; float proj_info[4]; - float ao_color[3]; - uint32_t max_voxel_gi_instances; + uint32_t max_voxel_gi_instances; uint32_t high_quality_vct; uint32_t orthogonal; - uint32_t pad[2]; + uint32_t pad; float cam_rotation[12]; }; diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index fa66ed85a9..ae8d91a73b 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -48,8 +48,8 @@ void get_vogel_disk(float *r_kernel, int p_sample_count) { } void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment, const Vector3 &p_world_position) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment); - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); bool needs_sdfgi = env && env->sdfgi_enabled; if (!needs_sdfgi) { @@ -83,7 +83,7 @@ void RendererSceneRenderRD::sdfgi_update(RID p_render_buffers, RID p_environment } int RendererSceneRenderRD::sdfgi_get_pending_region_count(RID p_render_buffers) const { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(rb == nullptr, 0); @@ -113,7 +113,7 @@ AABB RendererSceneRenderRD::sdfgi_get_pending_region_bounds(RID p_render_buffers AABB bounds; Vector3i from; Vector3i size; - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(rb == nullptr, AABB()); ERR_FAIL_COND_V(rb->sdfgi == nullptr, AABB()); @@ -126,7 +126,7 @@ uint32_t RendererSceneRenderRD::sdfgi_get_pending_region_cascade(RID p_render_bu AABB bounds; Vector3i from; Vector3i size; - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(rb == nullptr, -1); ERR_FAIL_COND_V(rb->sdfgi == nullptr, -1); @@ -164,139 +164,133 @@ void RendererSceneRenderRD::environment_initialize(RID p_rid) { } void RendererSceneRenderRD::environment_set_background(RID p_env, RS::EnvironmentBG p_bg) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->background = p_bg; } void RendererSceneRenderRD::environment_set_sky(RID p_env, RID p_sky) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->sky = p_sky; } void RendererSceneRenderRD::environment_set_sky_custom_fov(RID p_env, float p_scale) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->sky_custom_fov = p_scale; } void RendererSceneRenderRD::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->sky_orientation = p_orientation; } void RendererSceneRenderRD::environment_set_bg_color(RID p_env, const Color &p_color) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->bg_color = p_color; } void RendererSceneRenderRD::environment_set_bg_energy(RID p_env, float p_energy) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->bg_energy = p_energy; } void RendererSceneRenderRD::environment_set_canvas_max_layer(RID p_env, int p_max_layer) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->canvas_max_layer = p_max_layer; } -void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source, const Color &p_ao_color) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); +void RendererSceneRenderRD::environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient, float p_energy, float p_sky_contribution, RS::EnvironmentReflectionSource p_reflection_source) { + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); - env->set_ambient_light(p_color, p_ambient, p_energy, p_sky_contribution, p_reflection_source, p_ao_color); + env->set_ambient_light(p_color, p_ambient, p_energy, p_sky_contribution, p_reflection_source); } RS::EnvironmentBG RendererSceneRenderRD::environment_get_background(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, RS::ENV_BG_MAX); return env->background; } RID RendererSceneRenderRD::environment_get_sky(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, RID()); return env->sky; } float RendererSceneRenderRD::environment_get_sky_custom_fov(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->sky_custom_fov; } Basis RendererSceneRenderRD::environment_get_sky_orientation(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, Basis()); return env->sky_orientation; } Color RendererSceneRenderRD::environment_get_bg_color(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, Color()); return env->bg_color; } float RendererSceneRenderRD::environment_get_bg_energy(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->bg_energy; } int RendererSceneRenderRD::environment_get_canvas_max_layer(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->canvas_max_layer; } Color RendererSceneRenderRD::environment_get_ambient_light_color(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, Color()); return env->ambient_light; } RS::EnvironmentAmbientSource RendererSceneRenderRD::environment_get_ambient_source(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, RS::ENV_AMBIENT_SOURCE_BG); return env->ambient_source; } float RendererSceneRenderRD::environment_get_ambient_light_energy(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->ambient_light_energy; } float RendererSceneRenderRD::environment_get_ambient_sky_contribution(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->ambient_sky_contribution; } RS::EnvironmentReflectionSource RendererSceneRenderRD::environment_get_reflection_source(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, RS::ENV_REFLECTION_SOURCE_DISABLED); return env->reflection_source; } -Color RendererSceneRenderRD::environment_get_ao_color(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); - ERR_FAIL_COND_V(!env, Color()); - return env->ao_color; -} - void RendererSceneRenderRD::environment_set_tonemap(RID p_env, RS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->set_tonemap(p_tone_mapper, p_exposure, p_white, p_auto_exposure, p_min_luminance, p_max_luminance, p_auto_exp_speed, p_auto_exp_scale); } void RendererSceneRenderRD::environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->set_glow(p_enable, p_levels, p_intensity, p_strength, p_mix, p_bloom_threshold, p_blend_mode, p_hdr_bleed_threshold, p_hdr_bleed_scale, p_hdr_luminance_cap); } @@ -310,7 +304,7 @@ void RendererSceneRenderRD::environment_glow_set_use_high_quality(bool p_enable) } void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS::EnvironmentSDFGICascades p_cascades, float p_min_cell_size, RS::EnvironmentSDFGIYScale p_y_scale, bool p_use_occlusion, float p_bounce_feedback, bool p_read_sky, float p_energy, float p_normal_bias, float p_probe_bias) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); if (!is_dynamic_gi_supported()) { @@ -321,65 +315,65 @@ void RendererSceneRenderRD::environment_set_sdfgi(RID p_env, bool p_enable, RS:: } void RendererSceneRenderRD::environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_fog_aerial_perspective) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->set_fog(p_enable, p_light_color, p_light_energy, p_sun_scatter, p_density, p_height, p_height_density, p_fog_aerial_perspective); } bool RendererSceneRenderRD::environment_is_fog_enabled(RID p_env) const { - const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, false); return env->fog_enabled; } Color RendererSceneRenderRD::environment_get_fog_light_color(RID p_env) const { - const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, Color()); return env->fog_light_color; } float RendererSceneRenderRD::environment_get_fog_light_energy(RID p_env) const { - const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_light_energy; } float RendererSceneRenderRD::environment_get_fog_sun_scatter(RID p_env) const { - const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_sun_scatter; } float RendererSceneRenderRD::environment_get_fog_density(RID p_env) const { - const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_density; } float RendererSceneRenderRD::environment_get_fog_height(RID p_env) const { - const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_height; } float RendererSceneRenderRD::environment_get_fog_height_density(RID p_env) const { - const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_height_density; } float RendererSceneRenderRD::environment_get_fog_aerial_perspective(RID p_env) const { - const RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + const RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0); return env->fog_aerial_perspective; } -void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); +void RendererSceneRenderRD::environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) { + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); if (!is_volumetric_supported()) { return; } - env->set_volumetric_fog(p_enable, p_density, p_light, p_light_energy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount); + env->set_volumetric_fog(p_enable, p_density, p_albedo, p_emission, p_emission_energy, p_anisotropy, p_length, p_detail_spread, p_gi_inject, p_temporal_reprojection, p_temporal_reprojection_amount, p_ambient_inject); } void RendererSceneRenderRD::environment_set_volumetric_fog_volume_size(int p_size, int p_depth) { @@ -403,7 +397,7 @@ void RendererSceneRenderRD::environment_set_sdfgi_frames_to_update_light(RS::Env } void RendererSceneRenderRD::environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->set_ssr(p_enable, p_max_steps, p_fade_int, p_fade_out, p_depth_tolerance); @@ -418,7 +412,7 @@ RS::EnvironmentSSRRoughnessQuality RendererSceneRenderRD::environment_get_ssr_ro } void RendererSceneRenderRD::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_power, float p_detail, float p_horizon, float p_sharpness, float p_light_affect, float p_ao_channel_affect) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->set_ssao(p_enable, p_radius, p_intensity, p_power, p_detail, p_horizon, p_sharpness, p_light_affect, p_ao_channel_affect); @@ -434,30 +428,30 @@ void RendererSceneRenderRD::environment_set_ssao_quality(RS::EnvironmentSSAOQual } bool RendererSceneRenderRD::environment_is_ssao_enabled(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, false); return env->ssao_enabled; } float RendererSceneRenderRD::environment_get_ssao_ao_affect(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0.0); return env->ssao_ao_channel_affect; } float RendererSceneRenderRD::environment_get_ssao_light_affect(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, 0.0); return env->ssao_direct_light_affect; } bool RendererSceneRenderRD::environment_is_ssr_enabled(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, false); return env->ssr_enabled; } bool RendererSceneRenderRD::environment_is_sdfgi_enabled(RID p_env) const { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, false); return env->sdfgi_enabled; } @@ -467,7 +461,7 @@ bool RendererSceneRenderRD::is_environment(RID p_env) const { } Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND_V(!env, Ref<Image>()); if (env->background == RS::ENV_BG_CAMERA_FEED || env->background == RS::ENV_BG_CANVAS || env->background == RS::ENV_BG_KEEP) { @@ -505,6 +499,37 @@ Ref<Image> RendererSceneRenderRD::environment_bake_panorama(RID p_env, bool p_ba //////////////////////////////////////////////////////////// +RID RendererSceneRenderRD::fog_volume_instance_create(RID p_fog_volume) { + FogVolumeInstance fvi; + fvi.volume = p_fog_volume; + return fog_volume_instance_owner.make_rid(fvi); +} +void RendererSceneRenderRD::fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) { + FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + ERR_FAIL_COND(!fvi); + fvi->transform = p_transform; +} +void RendererSceneRenderRD::fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) { + FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + ERR_FAIL_COND(!fvi); + fvi->active = p_active; +} + +RID RendererSceneRenderRD::fog_volume_instance_get_volume(RID p_fog_volume_instance) const { + FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + ERR_FAIL_COND_V(!fvi, RID()); + return fvi->volume; +} + +Vector3 RendererSceneRenderRD::fog_volume_instance_get_position(RID p_fog_volume_instance) const { + FogVolumeInstance *fvi = fog_volume_instance_owner.get_or_null(p_fog_volume_instance); + ERR_FAIL_COND_V(!fvi, Vector3()); + + return fvi->transform.get_origin(); +} + +//////////////////////////////////////////////////////////// + RID RendererSceneRenderRD::reflection_atlas_create() { ReflectionAtlas ra; ra.count = GLOBAL_GET("rendering/reflections/reflection_atlas/reflection_count"); @@ -522,7 +547,7 @@ RID RendererSceneRenderRD::reflection_atlas_create() { } void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) { - ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas); + ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas); ERR_FAIL_COND(!ra); if (ra->size == p_reflection_size && ra->count == p_reflection_count) { @@ -557,7 +582,7 @@ void RendererSceneRenderRD::reflection_atlas_set_size(RID p_ref_atlas, int p_ref } int RendererSceneRenderRD::reflection_atlas_get_size(RID p_ref_atlas) const { - ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_ref_atlas); + ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_ref_atlas); ERR_FAIL_COND_V(!ra, 0); return ra->size; @@ -573,7 +598,7 @@ RID RendererSceneRenderRD::reflection_probe_instance_create(RID p_probe) { } void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!rpi); rpi->transform = p_transform; @@ -581,13 +606,13 @@ void RendererSceneRenderRD::reflection_probe_instance_set_transform(RID p_instan } void RendererSceneRenderRD::reflection_probe_release_atlas_index(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!rpi); if (rpi->atlas.is_null()) { return; //nothing to release } - ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); ERR_FAIL_COND(!atlas); ERR_FAIL_INDEX(rpi->atlas_index, atlas->reflections.size()); atlas->reflections.write[rpi->atlas_index].owner = RID(); @@ -596,7 +621,7 @@ void RendererSceneRenderRD::reflection_probe_release_atlas_index(RID p_instance) } bool RendererSceneRenderRD::reflection_probe_instance_needs_redraw(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, false); if (rpi->rendering) { @@ -615,18 +640,18 @@ bool RendererSceneRenderRD::reflection_probe_instance_needs_redraw(RID p_instanc } bool RendererSceneRenderRD::reflection_probe_instance_has_reflection(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, false); return rpi->atlas.is_valid(); } bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { - ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_reflection_atlas); + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_reflection_atlas); ERR_FAIL_COND_V(!atlas, false); - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, false); RD::get_singleton()->draw_command_begin_label("Reflection probe render"); @@ -701,7 +726,7 @@ bool RendererSceneRenderRD::reflection_probe_instance_begin_render(RID p_instanc uint64_t pass_min = 0; for (int i = 0; i < atlas->reflections.size(); i++) { - ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.getornull(atlas->reflections[i].owner); + ReflectionProbeInstance *rpi2 = reflection_probe_instance_owner.get_or_null(atlas->reflections[i].owner); if (rpi2->last_pass < pass_min) { pass_min = rpi2->last_pass; rpi->atlas_index = i; @@ -733,12 +758,12 @@ RID RendererSceneRenderRD::reflection_probe_create_framebuffer(RID p_color, RID } bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, false); ERR_FAIL_COND_V(!rpi->rendering, false); ERR_FAIL_COND_V(rpi->atlas.is_null(), false); - ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); if (!atlas || rpi->atlas_index == -1) { //does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering) rpi->rendering = false; @@ -779,30 +804,30 @@ bool RendererSceneRenderRD::reflection_probe_instance_postprocess_step(RID p_ins } uint32_t RendererSceneRenderRD::reflection_probe_instance_get_resolution(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, 0); - ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); ERR_FAIL_COND_V(!atlas, 0); return atlas->size; } RID RendererSceneRenderRD::reflection_probe_instance_get_framebuffer(RID p_instance, int p_index) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, RID()); ERR_FAIL_INDEX_V(p_index, 6, RID()); - ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); ERR_FAIL_COND_V(!atlas, RID()); return atlas->reflections[rpi->atlas_index].fbs[p_index]; } RID RendererSceneRenderRD::reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, RID()); ERR_FAIL_INDEX_V(p_index, 6, RID()); - ReflectionAtlas *atlas = reflection_atlas_owner.getornull(rpi->atlas); + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(rpi->atlas); ERR_FAIL_COND_V(!atlas, RID()); return atlas->depth_fb; } @@ -829,7 +854,7 @@ void RendererSceneRenderRD::_update_shadow_atlas(ShadowAtlas *shadow_atlas) { } void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool p_16_bits) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(p_size < 0); p_size = next_power_of_2(p_size); @@ -850,8 +875,8 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool } //erase shadow atlas reference from lights - for (Map<RID, uint32_t>::Element *E = shadow_atlas->shadow_owners.front(); E; E = E->next()) { - LightInstance *li = light_instance_owner.getornull(E->key()); + for (const KeyValue<RID, uint32_t> &E : shadow_atlas->shadow_owners) { + LightInstance *li = light_instance_owner.get_or_null(E.key); ERR_CONTINUE(!li); li->shadow_atlases.erase(p_atlas); } @@ -864,7 +889,7 @@ void RendererSceneRenderRD::shadow_atlas_set_size(RID p_atlas, int p_size, bool } void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_INDEX(p_quadrant, 4); ERR_FAIL_INDEX(p_subdivision, 16384); @@ -886,7 +911,7 @@ void RendererSceneRenderRD::shadow_atlas_set_quadrant_subdivision(RID p_atlas, i for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) { if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) { shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); - LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); + LightInstance *li = light_instance_owner.get_or_null(shadow_atlas->quadrants[p_quadrant].shadows[i].owner); ERR_CONTINUE(!li); li->shadow_atlases.erase(p_atlas); } @@ -947,7 +972,7 @@ bool RendererSceneRenderRD::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, break; } - LightInstance *sli = light_instance_owner.getornull(sarr[j].owner); + LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner); ERR_CONTINUE(!sli); if (sli->last_scene_pass != scene_pass) { @@ -999,7 +1024,7 @@ bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_ uint64_t pass = 0; if (sarr[j].owner.is_valid()) { - LightInstance *sli = light_instance_owner.getornull(sarr[j].owner); + LightInstance *sli = light_instance_owner.get_or_null(sarr[j].owner); ERR_CONTINUE(!sli); if (sli->last_scene_pass == scene_pass) { @@ -1014,7 +1039,7 @@ bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_ } if (sarr[j + 1].owner.is_valid()) { - LightInstance *sli = light_instance_owner.getornull(sarr[j + 1].owner); + LightInstance *sli = light_instance_owner.get_or_null(sarr[j + 1].owner); ERR_CONTINUE(!sli); if (sli->last_scene_pass == scene_pass) { @@ -1053,10 +1078,10 @@ bool RendererSceneRenderRD::_shadow_atlas_find_omni_shadows(ShadowAtlas *shadow_ } bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND_V(!shadow_atlas, false); - LightInstance *li = light_instance_owner.getornull(p_light_intance); + LightInstance *li = light_instance_owner.get_or_null(p_light_intance); ERR_FAIL_COND_V(!li, false); if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) { @@ -1179,7 +1204,7 @@ bool RendererSceneRenderRD::shadow_atlas_update_light(RID p_atlas, RID p_light_i void RendererSceneRenderRD::_shadow_atlas_invalidate_shadow(RendererSceneRenderRD::ShadowAtlas::Quadrant::Shadow *p_shadow, RID p_atlas, RendererSceneRenderRD::ShadowAtlas *p_shadow_atlas, uint32_t p_quadrant, uint32_t p_shadow_idx) { if (p_shadow->owner.is_valid()) { - LightInstance *sli = light_instance_owner.getornull(p_shadow->owner); + LightInstance *sli = light_instance_owner.get_or_null(p_shadow->owner); uint32_t old_key = p_shadow_atlas->shadow_owners[p_shadow->owner]; if (old_key & ShadowAtlas::OMNI_LIGHT_FLAG) { @@ -1260,7 +1285,7 @@ int RendererSceneRenderRD::get_directional_light_shadow_size(RID p_light_intance Rect2i r = _get_directional_shadow_rect(directional_shadow.size, directional_shadow.light_count, 0); - LightInstance *light_instance = light_instance_owner.getornull(p_light_intance); + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_intance); ERR_FAIL_COND_V(!light_instance, 0); switch (storage->light_directional_get_shadow_mode(light_instance->light)) { @@ -1296,7 +1321,7 @@ void RendererSceneRenderRD::camera_effects_set_dof_blur_bokeh_shape(RS::DOFBokeh } void RendererSceneRenderRD::camera_effects_set_dof_blur(RID p_camera_effects, bool p_far_enable, float p_far_distance, float p_far_transition, bool p_near_enable, float p_near_distance, float p_near_transition, float p_amount) { - CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); + CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects); ERR_FAIL_COND(!camfx); camfx->dof_blur_far_enabled = p_far_enable; @@ -1311,7 +1336,7 @@ void RendererSceneRenderRD::camera_effects_set_dof_blur(RID p_camera_effects, bo } void RendererSceneRenderRD::camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) { - CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); + CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects); ERR_FAIL_COND(!camfx); camfx->override_exposure_enabled = p_enable; @@ -1321,7 +1346,7 @@ void RendererSceneRenderRD::camera_effects_set_custom_exposure(RID p_camera_effe RID RendererSceneRenderRD::light_instance_create(RID p_light) { RID li = light_instance_owner.make_rid(LightInstance()); - LightInstance *light_instance = light_instance_owner.getornull(li); + LightInstance *light_instance = light_instance_owner.get_or_null(li); light_instance->self = li; light_instance->light = p_light; @@ -1334,21 +1359,21 @@ RID RendererSceneRenderRD::light_instance_create(RID p_light) { } void RendererSceneRenderRD::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) { - LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->transform = p_transform; } void RendererSceneRenderRD::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) { - LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->aabb = p_aabb; } void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform3D &p_transform, float p_far, float p_split, int p_pass, float p_shadow_texel_size, float p_bias_scale, float p_range_begin, const Vector2 &p_uv_scale) { - LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); ERR_FAIL_COND(!light_instance); ERR_FAIL_INDEX(p_pass, 6); @@ -1364,7 +1389,7 @@ void RendererSceneRenderRD::light_instance_set_shadow_transform(RID p_light_inst } void RendererSceneRenderRD::light_instance_mark_visible(RID p_light_instance) { - LightInstance *light_instance = light_instance_owner.getornull(p_light_instance); + LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance); ERR_FAIL_COND(!light_instance); light_instance->last_scene_pass = scene_pass; @@ -1407,7 +1432,7 @@ RID RendererSceneRenderRD::decal_instance_create(RID p_decal) { } void RendererSceneRenderRD::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) { - DecalInstance *di = decal_instance_owner.getornull(p_decal); + DecalInstance *di = decal_instance_owner.get_or_null(p_decal); ERR_FAIL_COND(!di); di->transform = p_transform; } @@ -1420,7 +1445,7 @@ RID RendererSceneRenderRD::lightmap_instance_create(RID p_lightmap) { return lightmap_instance_owner.make_rid(li); } void RendererSceneRenderRD::lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) { - LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap); + LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap); ERR_FAIL_COND(!li); li->transform = p_transform; } @@ -1452,7 +1477,7 @@ void RendererSceneRenderRD::voxel_gi_update(RID p_probe, bool p_update_light_ins } void RendererSceneRenderRD::_debug_sdfgi_probes(RID p_render_buffers, RD::DrawListID p_draw_list, RID p_framebuffer, const CameraMatrix &p_camera_with_transform) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); if (!rb->sdfgi) { @@ -1478,8 +1503,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { RD::TextureFormat tf; tf.format = _render_buffers_get_color_format(); // RD::DATA_FORMAT_R16G16B16A16_SFLOAT; - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D; tf.array_layers = rb->view_count; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; @@ -1490,6 +1515,10 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { } tf.mipmaps = mipmaps_required; + rb->sss_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + tf.width = rb->internal_width; + tf.height = rb->internal_height; rb->blur[0].texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); //the second one is smaller (only used for separatable part of blur) tf.width >>= 1; @@ -1497,8 +1526,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { tf.mipmaps--; rb->blur[1].texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); - int base_width = rb->width; - int base_height = rb->height; + int base_width = rb->internal_width; + int base_height = rb->internal_height; for (uint32_t i = 0; i < mipmaps_required; i++) { RenderBuffers::Blur::Mipmap mm; @@ -1552,8 +1581,8 @@ void RendererSceneRenderRD::_allocate_blur_textures(RenderBuffers *rb) { // create 4 weight textures, 2 full size, 2 half size tf.format = RD::DATA_FORMAT_R16_SFLOAT; // We could probably use DATA_FORMAT_R8_SNORM if we don't pre-multiply by blur_size but that depends on whether we can remove DEPTH_GAP - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; tf.texture_type = rb->view_count > 1 ? RD::TEXTURE_TYPE_2D_ARRAY : RD::TEXTURE_TYPE_2D; tf.array_layers = rb->view_count; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; @@ -1631,8 +1660,8 @@ void RendererSceneRenderRD::_allocate_depth_backbuffer_textures(RenderBuffers *r void RendererSceneRenderRD::_allocate_luminance_textures(RenderBuffers *rb) { ERR_FAIL_COND(!rb->luminance.current.is_null()); - int w = rb->width; - int h = rb->height; + int w = rb->internal_width; + int h = rb->internal_height; while (true) { w = MAX(w / 8, 1); @@ -1684,9 +1713,26 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->texture_fb = RID(); } - if (rb->texture.is_valid()) { - RD::get_singleton()->free(rb->texture); + if (rb->internal_texture == rb->texture && rb->internal_texture.is_valid()) { + RD::get_singleton()->free(rb->internal_texture); rb->texture = RID(); + rb->internal_texture = RID(); + rb->upscale_texture = RID(); + } else { + if (rb->texture.is_valid()) { + RD::get_singleton()->free(rb->texture); + rb->texture = RID(); + } + + if (rb->internal_texture.is_valid()) { + RD::get_singleton()->free(rb->internal_texture); + rb->internal_texture = RID(); + } + + if (rb->upscale_texture.is_valid()) { + RD::get_singleton()->free(rb->upscale_texture); + rb->upscale_texture = RID(); + } } if (rb->depth_texture.is_valid()) { @@ -1704,6 +1750,11 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { rb->depth_back_texture = RID(); } + if (rb->sss_texture.is_valid()) { + RD::get_singleton()->free(rb->sss_texture); + rb->sss_texture = RID(); + } + for (int i = 0; i < 2; i++) { for (int m = 0; m < rb->blur[i].mipmaps.size(); m++) { // do we free the texture slice here? or is it enough to free the main texture? @@ -1790,10 +1841,10 @@ void RendererSceneRenderRD::_free_render_buffer_data(RenderBuffers *rb) { } void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatrix &p_camera) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); - bool can_use_effects = rb->width >= 8 && rb->height >= 8; + bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8; if (!can_use_effects) { //just copy @@ -1804,22 +1855,22 @@ void RendererSceneRenderRD::_process_sss(RID p_render_buffers, const CameraMatri _allocate_blur_textures(rb); } - storage->get_effects()->sub_surface_scattering(rb->texture, rb->blur[0].mipmaps[0].texture, rb->depth_texture, p_camera, Size2i(rb->width, rb->height), sss_scale, sss_depth_scale, sss_quality); + storage->get_effects()->sub_surface_scattering(rb->internal_texture, rb->sss_texture, rb->depth_texture, p_camera, Size2i(rb->internal_width, rb->internal_height), sss_scale, sss_depth_scale, sss_quality); } void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_framebuffer, RID p_normal_buffer, RID p_specular_buffer, RID p_metallic, const Color &p_metallic_mask, RID p_environment, const CameraMatrix &p_projection, bool p_use_additive) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); - bool can_use_effects = rb->width >= 8 && rb->height >= 8; + bool can_use_effects = rb->internal_width >= 8 && rb->internal_height >= 8; if (!can_use_effects) { //just copy - storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, RID()); + storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, RID()); return; } - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment); ERR_FAIL_COND(!env); ERR_FAIL_COND(!env->ssr_enabled); @@ -1827,8 +1878,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb if (rb->ssr.depth_scaled.is_null()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R32_SFLOAT; - tf.width = rb->width / 2; - tf.height = rb->height / 2; + tf.width = rb->internal_width / 2; + tf.height = rb->internal_height / 2; tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT; @@ -1842,8 +1893,8 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb if (ssr_roughness_quality != RS::ENV_SSR_ROUGNESS_QUALITY_DISABLED && !rb->ssr.blur_radius[0].is_valid()) { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; - tf.width = rb->width / 2; - tf.height = rb->height / 2; + tf.width = rb->internal_width / 2; + tf.height = rb->internal_height / 2; tf.texture_type = RD::TEXTURE_TYPE_2D; tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; @@ -1855,15 +1906,15 @@ void RendererSceneRenderRD::_process_ssr(RID p_render_buffers, RID p_dest_frameb _allocate_blur_textures(rb); } - storage->get_effects()->screen_space_reflection(rb->texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->width / 2, rb->height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection); - storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->texture, rb->blur[0].mipmaps[1].texture); + storage->get_effects()->screen_space_reflection(rb->internal_texture, p_normal_buffer, ssr_roughness_quality, rb->ssr.blur_radius[0], rb->ssr.blur_radius[1], p_metallic, p_metallic_mask, rb->depth_texture, rb->ssr.depth_scaled, rb->ssr.normal_scaled, rb->blur[0].mipmaps[1].texture, rb->blur[1].mipmaps[0].texture, Size2i(rb->internal_width / 2, rb->internal_height / 2), env->ssr_max_steps, env->ssr_fade_in, env->ssr_fade_out, env->ssr_depth_tolerance, p_projection); + storage->get_effects()->merge_specular(p_dest_framebuffer, p_specular_buffer, p_use_additive ? RID() : rb->internal_texture, rb->blur[0].mipmaps[1].texture); } void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environment, RID p_normal_buffer, const CameraMatrix &p_projection) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment); ERR_FAIL_COND(!env); RENDER_TIMESTAMP("Process SSAO"); @@ -1893,15 +1944,15 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen int half_width; int half_height; if (ssao_half_size) { - buffer_width = (rb->width + 3) / 4; - buffer_height = (rb->height + 3) / 4; - half_width = (rb->width + 7) / 8; - half_height = (rb->height + 7) / 8; + buffer_width = (rb->internal_width + 3) / 4; + buffer_height = (rb->internal_height + 3) / 4; + half_width = (rb->internal_width + 7) / 8; + half_height = (rb->internal_height + 7) / 8; } else { - buffer_width = (rb->width + 1) / 2; - buffer_height = (rb->height + 1) / 2; - half_width = (rb->width + 3) / 4; - half_height = (rb->height + 3) / 4; + buffer_width = (rb->internal_width + 1) / 2; + buffer_height = (rb->internal_height + 1) / 2; + half_width = (rb->internal_width + 3) / 4; + half_height = (rb->internal_height + 3) / 4; } bool uniform_sets_are_invalid = false; if (rb->ssao.depth.is_null()) { @@ -1973,8 +2024,8 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen { RD::TextureFormat tf; tf.format = RD::DATA_FORMAT_R8_UNORM; - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT; rb->ssao.ao_final = RD::get_singleton()->texture_create(tf, RD::TextureView()); RD::get_singleton()->set_resource_name(rb->ssao.ao_final, "SSAO Final"); @@ -1997,7 +2048,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen settings.blur_passes = ssao_blur_passes; settings.fadeout_from = ssao_fadeout_from; settings.fadeout_to = ssao_fadeout_to; - settings.full_screen_size = Size2i(rb->width, rb->height); + settings.full_screen_size = Size2i(rb->internal_width, rb->internal_height); settings.half_screen_size = Size2i(buffer_width, buffer_height); settings.quarter_screen_size = Size2i(half_width, half_height); @@ -2005,7 +2056,7 @@ void RendererSceneRenderRD::_process_ssao(RID p_render_buffers, RID p_environmen } void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderDataRD *p_render_data) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); ERR_FAIL_COND(!rb); RD::get_singleton()->draw_command_begin_label("Copy screen texture"); @@ -2034,7 +2085,7 @@ void RendererSceneRenderRD::_render_buffers_copy_screen_texture(const RenderData } void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataRD *p_render_data) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); ERR_FAIL_COND(!rb); RD::get_singleton()->draw_command_begin_label("Copy depth texture"); @@ -2057,12 +2108,12 @@ void RendererSceneRenderRD::_render_buffers_copy_depth_texture(const RenderDataR } void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const RenderDataRD *p_render_data) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); ERR_FAIL_COND(!rb); - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment); - //glow (if enabled) - CameraEffects *camfx = camera_effects_owner.getornull(p_render_data->camera_effects); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_render_data->environment); + // Glow and override exposure (if enabled). + CameraEffects *camfx = camera_effects_owner.get_or_null(p_render_data->camera_effects); bool can_use_effects = rb->width >= 8 && rb->height >= 8; bool can_use_storage = _render_buffers_can_be_storage(); @@ -2077,9 +2128,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende EffectsRD::BokehBuffers buffers; - // textures we use - buffers.base_texture_size = Size2i(rb->width, rb->height); - buffers.base_texture = rb->texture; + // Textures we use + buffers.base_texture_size = Size2i(rb->internal_width, rb->internal_height); + buffers.base_texture = rb->internal_texture; buffers.depth_texture = rb->depth_texture; buffers.secondary_texture = rb->blur[0].mipmaps[0].texture; buffers.half_texture[0] = rb->blur[1].mipmaps[0].texture; @@ -2089,7 +2140,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende if (can_use_storage) { storage->get_effects()->bokeh_dof(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, dof_blur_use_jitter, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); } else { - // set framebuffers + // Set framebuffers. buffers.base_fb = rb->texture_fb; buffers.secondary_fb = rb->weight_buffers[1].fb; buffers.half_fb[0] = rb->weight_buffers[2].fb; @@ -2099,7 +2150,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende buffers.weight_texture[2] = rb->weight_buffers[2].weight; buffers.weight_texture[3] = rb->weight_buffers[3].weight; - // set weight buffers + // Set weight buffers. buffers.base_weight_fb = rb->base_weight_fb; storage->get_effects()->bokeh_dof_raster(buffers, camfx->dof_blur_far_enabled, camfx->dof_blur_far_distance, camfx->dof_blur_far_transition, camfx->dof_blur_near_enabled, camfx->dof_blur_near_distance, camfx->dof_blur_near_transition, bokeh_size, dof_blur_bokeh_shape, dof_blur_quality, p_render_data->z_near, p_render_data->z_far, p_render_data->cam_ortogonal); @@ -2118,17 +2169,17 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende double step = env->auto_exp_speed * time_step; if (can_use_storage) { - storage->get_effects()->luminance_reduction(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); + storage->get_effects()->luminance_reduction(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); } else { - storage->get_effects()->luminance_reduction_raster(rb->texture, Size2i(rb->width, rb->height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); + storage->get_effects()->luminance_reduction_raster(rb->internal_texture, Size2i(rb->internal_width, rb->internal_height), rb->luminance.reduce, rb->luminance.fb, rb->luminance.current, env->min_luminance, env->max_luminance, step, set_immediate); } - //swap final reduce with prev luminance + // Swap final reduce with prev luminance. SWAP(rb->luminance.current, rb->luminance.reduce.write[rb->luminance.reduce.size() - 1]); if (!can_use_storage) { SWAP(rb->luminance.current_fb, rb->luminance.fb.write[rb->luminance.fb.size() - 1]); } - RenderingServerDefault::redraw_request(); //redraw all the time if auto exposure rendering is on + RenderingServerDefault::redraw_request(); // Redraw all the time if auto exposure rendering is on. RD::get_singleton()->draw_command_end_label(); } @@ -2163,9 +2214,9 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende luminance_texture = rb->luminance.current; } if (can_use_storage) { - storage->get_effects()->gaussian_glow(rb->texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + storage->get_effects()->gaussian_glow(rb->internal_texture, rb->blur[1].mipmaps[i].texture, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); } else { - storage->get_effects()->gaussian_glow_raster(rb->texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); + storage->get_effects()->gaussian_glow_raster(rb->internal_texture, rb->blur[1].mipmaps[i].half_fb, rb->blur[1].mipmaps[i].half_texture, rb->blur[1].mipmaps[i].fb, Size2i(vp_w, vp_h), env->glow_strength, glow_high_quality, true, env->glow_hdr_luminance_cap, env->exposure, env->glow_bloom, env->glow_hdr_bleed_threshold, env->glow_hdr_bleed_scale, luminance_texture, env->auto_exp_scale); } } else { if (can_use_storage) { @@ -2182,7 +2233,6 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende { RD::get_singleton()->draw_command_begin_label("Tonemap"); - //tonemap EffectsRD::TonemapSettings tonemap; if (can_use_effects && env && env->auto_exposure && rb->luminance.current.is_valid()) { @@ -2213,7 +2263,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende } tonemap.use_debanding = rb->use_debanding; - tonemap.texture_size = Vector2i(rb->width, rb->height); + tonemap.texture_size = Vector2i(rb->internal_width, rb->internal_height); if (env) { tonemap.tonemap_mode = env->tone_mapper; @@ -2221,6 +2271,10 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.exposure = env->exposure; } + if (camfx && camfx->override_exposure_enabled) { + tonemap.exposure = camfx->override_exposure; + } + tonemap.use_color_correction = false; tonemap.use_1d_color_correction = false; tonemap.color_correction_texture = storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_3D_WHITE); @@ -2240,7 +2294,15 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende tonemap.luminance_multiplier = _render_buffers_get_luminance_multiplier(); tonemap.view_count = p_render_data->view_count; - storage->get_effects()->tonemapper(rb->texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); + storage->get_effects()->tonemapper(rb->internal_texture, storage->render_target_get_rd_framebuffer(rb->render_target), tonemap); + + RD::get_singleton()->draw_command_end_label(); + } + + if (can_use_effects && can_use_storage && (rb->internal_width != rb->width || rb->internal_height != rb->height)) { + RD::get_singleton()->draw_command_begin_label("FSR Upscale"); + + storage->get_effects()->fsr_upscale(rb->internal_texture, rb->upscale_texture, rb->texture, Size2i(rb->internal_width, rb->internal_height), Size2i(rb->width, rb->height), rb->fsr_sharpness); RD::get_singleton()->draw_command_end_label(); } @@ -2251,10 +2313,12 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_framebuffer, const RenderDataRD *p_render_data) { RD::get_singleton()->draw_command_begin_label("Post Process Subpass"); - RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); ERR_FAIL_COND(!rb); - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_render_data->environment); + // Override exposure (if enabled). + CameraEffects *camfx = camera_effects_owner.get_or_null(p_render_data->camera_effects); bool can_use_effects = rb->width >= 8 && rb->height >= 8; @@ -2268,6 +2332,10 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr tonemap.white = env->white; } + if (camfx && camfx->override_exposure_enabled) { + tonemap.exposure = camfx->override_exposure; + } + // We don't support glow or auto exposure here, if they are needed, don't use subpasses! // The problem is that we need to use the result so far and process them before we can // apply this to our results. @@ -2311,7 +2379,7 @@ void RendererSceneRenderRD::_post_process_subpass(RID p_source_texture, RID p_fr } void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_data) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); ERR_FAIL_COND(!rb); storage->render_target_disable_clear_request(rb->render_target); @@ -2320,7 +2388,7 @@ void RendererSceneRenderRD::_disable_clear_request(const RenderDataRD *p_render_ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID p_shadow_atlas, RID p_occlusion_buffer) { EffectsRD *effects = storage->get_effects(); - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); if (debug_draw == RS::VIEWPORT_DEBUG_DRAW_SHADOW_ATLAS) { @@ -2386,7 +2454,7 @@ void RendererSceneRenderRD::_render_buffers_debug_draw(RID p_render_buffers, RID } void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, bool p_use_1d_color_correction, RID p_color_correction) { - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_env); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_env); ERR_FAIL_COND(!env); env->adjustments_enabled = p_enable; @@ -2398,7 +2466,7 @@ void RendererSceneRenderRD::environment_set_adjustment(RID p_env, bool p_enable, } RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_buffers) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); if (!rb->blur[0].texture.is_valid()) { return RID(); //not valid at the moment @@ -2407,7 +2475,7 @@ RID RendererSceneRenderRD::render_buffers_get_back_buffer_texture(RID p_render_b } RID RendererSceneRenderRD::render_buffers_get_back_depth_texture(RID p_render_buffers) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); if (!rb->depth_back_texture.is_valid()) { return RID(); //not valid at the moment @@ -2415,15 +2483,22 @@ RID RendererSceneRenderRD::render_buffers_get_back_depth_texture(RID p_render_bu return rb->depth_back_texture; } +RID RendererSceneRenderRD::render_buffers_get_depth_texture(RID p_render_buffers) { + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); + ERR_FAIL_COND_V(!rb, RID()); + + return rb->depth_texture; +} + RID RendererSceneRenderRD::render_buffers_get_ao_texture(RID p_render_buffers) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); return rb->ssao.ao_final; } RID RendererSceneRenderRD::render_buffers_get_voxel_gi_buffer(RID p_render_buffers) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); if (rb->gi.voxel_gi_buffer.is_null()) { rb->gi.voxel_gi_buffer = RD::get_singleton()->uniform_buffer_create(sizeof(RendererSceneGIRD::VoxelGIData) * RendererSceneGIRD::MAX_VOXEL_GI_INSTANCES); @@ -2436,31 +2511,31 @@ RID RendererSceneRenderRD::render_buffers_get_default_voxel_gi_buffer() { } RID RendererSceneRenderRD::render_buffers_get_gi_ambient_texture(RID p_render_buffers) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); return rb->ambient_buffer; } RID RendererSceneRenderRD::render_buffers_get_gi_reflection_texture(RID p_render_buffers) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); return rb->reflection_buffer; } uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_count(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); return rb->sdfgi->cascades.size(); } bool RendererSceneRenderRD::render_buffers_is_sdfgi_enabled(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, false); return rb->sdfgi != nullptr; } RID RendererSceneRenderRD::render_buffers_get_sdfgi_irradiance_probes(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); ERR_FAIL_COND_V(!rb->sdfgi, RID()); @@ -2468,7 +2543,7 @@ RID RendererSceneRenderRD::render_buffers_get_sdfgi_irradiance_probes(RID p_rend } Vector3 RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_offset(RID p_render_buffers, uint32_t p_cascade) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, Vector3()); ERR_FAIL_COND_V(!rb->sdfgi, Vector3()); ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3()); @@ -2477,7 +2552,7 @@ Vector3 RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_offset(RID p_ren } Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RID p_render_buffers, uint32_t p_cascade) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, Vector3i()); ERR_FAIL_COND_V(!rb->sdfgi, Vector3i()); ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), Vector3i()); @@ -2487,14 +2562,14 @@ Vector3i RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_offset(RI } float RendererSceneRenderRD::render_buffers_get_sdfgi_normal_bias(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); return rb->sdfgi->normal_bias; } float RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_render_buffers, uint32_t p_cascade) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); ERR_FAIL_UNSIGNED_INDEX_V(p_cascade, rb->sdfgi->cascades.size(), 0); @@ -2502,7 +2577,7 @@ float RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_size(RID p_r return float(rb->sdfgi->cascade_size) * rb->sdfgi->cascades[p_cascade].cell_size / float(rb->sdfgi->probe_axis_count - 1); } uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_count(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); @@ -2510,7 +2585,7 @@ uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_probe_count(RID } uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_size(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, 0); ERR_FAIL_COND_V(!rb->sdfgi, 0); @@ -2518,7 +2593,7 @@ uint32_t RendererSceneRenderRD::render_buffers_get_sdfgi_cascade_size(RID p_rend } bool RendererSceneRenderRD::render_buffers_is_sdfgi_using_occlusion(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, false); ERR_FAIL_COND_V(!rb->sdfgi, false); @@ -2526,14 +2601,14 @@ bool RendererSceneRenderRD::render_buffers_is_sdfgi_using_occlusion(RID p_render } float RendererSceneRenderRD::render_buffers_get_sdfgi_energy(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, 0.0); ERR_FAIL_COND_V(!rb->sdfgi, 0.0); return rb->sdfgi->energy; } RID RendererSceneRenderRD::render_buffers_get_sdfgi_occlusion_texture(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); ERR_FAIL_COND_V(!rb->sdfgi, RID()); @@ -2541,20 +2616,20 @@ RID RendererSceneRenderRD::render_buffers_get_sdfgi_occlusion_texture(RID p_rend } bool RendererSceneRenderRD::render_buffers_has_volumetric_fog(RID p_render_buffers) const { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, false); return rb->volumetric_fog != nullptr; } RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_texture(RID p_render_buffers) { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, RID()); return rb->volumetric_fog->fog_map; } RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID p_render_buffers) { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, RID()); if (!rb->volumetric_fog) { @@ -2565,12 +2640,12 @@ RID RendererSceneRenderRD::render_buffers_get_volumetric_fog_sky_uniform_set(RID } float RendererSceneRenderRD::render_buffers_get_volumetric_fog_end(RID p_render_buffers) { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0); return rb->volumetric_fog->length; } float RendererSceneRenderRD::render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers) { - const RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + const RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb || !rb->volumetric_fog, 0); return rb->volumetric_fog->spread; } @@ -2587,14 +2662,28 @@ bool RendererSceneRenderRD::_render_buffers_can_be_storage() { return true; } -void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { +void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) { ERR_FAIL_COND_MSG(p_view_count == 0, "Must have at least 1 view"); - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + if (!_render_buffers_can_be_storage()) { + p_internal_height = p_height; + p_internal_width = p_width; + } + + if (p_width != p_internal_width) { + float fsr_mipmap_bias = -log2f(p_width / p_internal_width) + p_fsr_mipmap_bias; + storage->sampler_rd_configure_custom(fsr_mipmap_bias); + update_uniform_sets(); + } + + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); // Should we add an overrule per viewport? + rb->internal_width = p_internal_width; + rb->internal_height = p_internal_height; rb->width = p_width; rb->height = p_height; + rb->fsr_sharpness = p_fsr_sharpness; rb->render_target = p_render_target; rb->msaa = p_msaa; rb->screen_space_aa = p_screen_space_aa; @@ -2616,8 +2705,8 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p tf.texture_type = RD::TEXTURE_TYPE_2D_ARRAY; } tf.format = _render_buffers_get_color_format(); - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; // If set to rb->width, msaa won't crash + tf.height = rb->internal_height; // If set to rb->width, msaa won't crash tf.array_layers = rb->view_count; // create a layer for every view tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT | (_render_buffers_can_be_storage() ? RD::TEXTURE_USAGE_STORAGE_BIT : 0) | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT; if (rb->msaa != RS::VIEWPORT_MSAA_DISABLED) { @@ -2625,7 +2714,17 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p } tf.usage_bits |= RD::TEXTURE_USAGE_INPUT_ATTACHMENT_BIT; // only needed when using subpasses in the mobile renderer - rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->internal_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + + if ((p_internal_width != p_width || p_internal_height != p_height)) { + tf.width = rb->width; + tf.height = rb->height; + rb->texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + rb->upscale_texture = RD::get_singleton()->texture_create(tf, RD::TextureView()); + } else { + rb->texture = rb->internal_texture; + rb->upscale_texture = rb->internal_texture; + } } { @@ -2639,8 +2738,8 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p tf.format = RD::DATA_FORMAT_R32_SFLOAT; } - tf.width = rb->width; - tf.height = rb->height; + tf.width = rb->internal_width; + tf.height = rb->internal_height; tf.usage_bits = RD::TEXTURE_USAGE_SAMPLING_BIT; tf.array_layers = rb->view_count; // create a layer for every view @@ -2656,16 +2755,16 @@ void RendererSceneRenderRD::render_buffers_configure(RID p_render_buffers, RID p if (!_render_buffers_can_be_storage()) { // ONLY USED ON MOBILE RENDERER, ONLY USED FOR POST EFFECTS! Vector<RID> fb; - fb.push_back(rb->texture); + fb.push_back(rb->internal_texture); rb->texture_fb = RD::get_singleton()->framebuffer_create(fb, RenderingDevice::INVALID_ID, rb->view_count); } RID target_texture = storage->render_target_get_rd_texture(rb->render_target); - rb->data->configure(rb->texture, rb->depth_texture, target_texture, rb->width, rb->height, p_msaa, p_view_count); + rb->data->configure(rb->internal_texture, rb->depth_texture, target_texture, p_internal_width, p_internal_height, p_msaa, p_view_count); if (is_clustered_enabled()) { - rb->cluster_builder->setup(Size2i(rb->width, rb->height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->texture); + rb->cluster_builder->setup(Size2i(p_internal_width, p_internal_height), max_cluster_elements, rb->depth_texture, storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED), rb->internal_texture); } } @@ -2695,9 +2794,14 @@ void RendererSceneRenderRD::shadows_quality_set(RS::ShadowQuality p_quality) { switch (shadows_quality) { case RS::SHADOW_QUALITY_HARD: { penumbra_shadow_samples = 4; - soft_shadow_samples = 1; + soft_shadow_samples = 0; shadows_quality_radius = 1.0; } break; + case RS::SHADOW_QUALITY_SOFT_VERY_LOW: { + penumbra_shadow_samples = 4; + soft_shadow_samples = 1; + shadows_quality_radius = 1.5; + } break; case RS::SHADOW_QUALITY_SOFT_LOW: { penumbra_shadow_samples = 8; soft_shadow_samples = 4; @@ -2737,9 +2841,14 @@ void RendererSceneRenderRD::directional_shadow_quality_set(RS::ShadowQuality p_q switch (directional_shadow_quality) { case RS::SHADOW_QUALITY_HARD: { directional_penumbra_shadow_samples = 4; - directional_soft_shadow_samples = 1; + directional_soft_shadow_samples = 0; directional_shadow_quality_radius = 1.0; } break; + case RS::SHADOW_QUALITY_SOFT_VERY_LOW: { + directional_penumbra_shadow_samples = 4; + directional_soft_shadow_samples = 1; + directional_shadow_quality_radius = 1.5; + } break; case RS::SHADOW_QUALITY_SOFT_LOW: { directional_penumbra_shadow_samples = 8; directional_soft_shadow_samples = 4; @@ -2794,7 +2903,7 @@ bool RendererSceneRenderRD::is_using_radiance_cubemap_array() const { } RendererSceneRenderRD::RenderBufferData *RendererSceneRenderRD::render_buffers_get_data(RID p_render_buffers) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND_V(!rb, nullptr); return rb->data; } @@ -2807,7 +2916,7 @@ void RendererSceneRenderRD::_setup_reflections(const PagedArray<RID> &p_reflecti break; } - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflections[i]); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_reflections[i]); if (!rpi) { continue; } @@ -2885,7 +2994,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const r_positional_light_count = 0; sky.sky_scene_state.ubo.directional_light_count = 0; - Plane camera_plane(p_camera_transform.origin, -p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized()); + Plane camera_plane(-p_camera_transform.basis.get_axis(Vector3::AXIS_Z).normalized(), p_camera_transform.origin); cluster.omni_light_count = 0; cluster.spot_light_count = 0; @@ -2893,7 +3002,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const r_directional_light_soft_shadows = false; for (int i = 0; i < (int)p_lights.size(); i++) { - LightInstance *li = light_instance_owner.getornull(p_lights[i]); + LightInstance *li = light_instance_owner.get_or_null(p_lights[i]); if (!li) { continue; } @@ -3025,7 +3134,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const RS::LightDirectionalShadowMode smode = storage->light_directional_get_shadow_mode(base); int limit = smode == RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL ? 0 : (smode == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS ? 1 : 3); - light_data.blend_splits = storage->light_directional_get_blend_splits(base); + light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && storage->light_directional_get_blend_splits(base); for (int j = 0; j < 4; j++) { Rect2 atlas_rect = li->shadow_transform[j].atlas_rect; CameraMatrix matrix = li->shadow_transform[j].camera; @@ -3122,7 +3231,7 @@ void RendererSceneRenderRD::_setup_lights(const PagedArray<RID> &p_lights, const ShadowAtlas *shadow_atlas = nullptr; if (p_shadow_atlas.is_valid() && p_using_shadows) { - shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); } bool using_forward_ids = _uses_forward_ids(); @@ -3305,7 +3414,7 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const break; } - DecalInstance *di = decal_instance_owner.getornull(p_decals[i]); + DecalInstance *di = decal_instance_owner.get_or_null(p_decals[i]); if (!di) { continue; } @@ -3365,7 +3474,7 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const Vector3 decal_extents = storage->decal_get_extents(decal); Transform3D scale_xform; - scale_xform.basis.scale(Vector3(decal_extents.x, decal_extents.y, decal_extents.z)); + scale_xform.basis.scale(decal_extents); Transform3D to_decal_xform = (p_camera_inverse_xform * di->transform * scale_xform * uv_xform).affine_inverse(); RendererStorageRD::store_transform(to_decal_xform, dd.xform); @@ -3461,6 +3570,189 @@ void RendererSceneRenderRD::_setup_decals(const PagedArray<RID> &p_decals, const } } +//////////////////////////////////////////////////////////////////////////////// +// FOG SHADER + +void RendererSceneRenderRD::FogShaderData::set_code(const String &p_code) { + //compile + + code = p_code; + valid = false; + ubo_size = 0; + uniforms.clear(); + + if (code == String()) { + return; //just invalid, but no error + } + + ShaderCompilerRD::GeneratedCode gen_code; + ShaderCompilerRD::IdentifierActions actions; + actions.entry_point_stages["fog"] = ShaderCompilerRD::STAGE_COMPUTE; + + uses_time = false; + + actions.usage_flag_pointers["TIME"] = &uses_time; + + actions.uniforms = &uniforms; + + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + + Error err = scene_singleton->volumetric_fog.compiler.compile(RS::SHADER_FOG, code, &actions, path, gen_code); + ERR_FAIL_COND_MSG(err != OK, "Fog shader compilation failed."); + + if (version.is_null()) { + version = scene_singleton->volumetric_fog.shader.version_create(); + } + + scene_singleton->volumetric_fog.shader.version_set_compute_code(version, gen_code.code, gen_code.uniforms, gen_code.stage_globals[ShaderCompilerRD::STAGE_COMPUTE], gen_code.defines); + ERR_FAIL_COND(!scene_singleton->volumetric_fog.shader.version_is_valid(version)); + + ubo_size = gen_code.uniform_total_size; + ubo_offsets = gen_code.uniform_offsets; + texture_uniforms = gen_code.texture_uniforms; + + pipeline = RD::get_singleton()->compute_pipeline_create(scene_singleton->volumetric_fog.shader.version_get_shader(version, 0)); + + valid = true; +} + +void RendererSceneRenderRD::FogShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { + if (!p_texture.is_valid()) { + if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { + default_texture_params[p_name].erase(p_index); + + if (default_texture_params[p_name].is_empty()) { + default_texture_params.erase(p_name); + } + } + } else { + if (!default_texture_params.has(p_name)) { + default_texture_params[p_name] = Map<int, RID>(); + } + default_texture_params[p_name][p_index] = p_texture; + } +} + +void RendererSceneRenderRD::FogShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { + Map<int, StringName> order; + + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + if (E->get().texture_order >= 0) { + order[E->get().texture_order + 100000] = E->key(); + } else { + order[E->get().order] = E->key(); + } + } + + for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); + pi.name = E->get(); + p_param_list->push_back(pi); + } +} + +void RendererSceneRenderRD::FogShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { + for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { + if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + continue; + } + + RendererStorage::InstanceShaderParam p; + p.info = ShaderLanguage::uniform_to_property_info(E->get()); + p.info.name = E->key(); //supply name + p.index = E->get().instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().array_size, E->get().hint); + p_param_list->push_back(p); + } +} + +bool RendererSceneRenderRD::FogShaderData::is_param_texture(const StringName &p_param) const { + if (!uniforms.has(p_param)) { + return false; + } + + return uniforms[p_param].texture_order >= 0; +} + +bool RendererSceneRenderRD::FogShaderData::is_animated() const { + return false; +} + +bool RendererSceneRenderRD::FogShaderData::casts_shadows() const { + return false; +} + +Variant RendererSceneRenderRD::FogShaderData::get_default_parameter(const StringName &p_parameter) const { + if (uniforms.has(p_parameter)) { + ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; + Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); + } + return Variant(); +} + +RS::ShaderNativeSourceCode RendererSceneRenderRD::FogShaderData::get_native_source_code() const { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + + return scene_singleton->volumetric_fog.shader.version_get_native_source_code(version); +} + +RendererSceneRenderRD::FogShaderData::FogShaderData() { + valid = false; +} + +RendererSceneRenderRD::FogShaderData::~FogShaderData() { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + ERR_FAIL_COND(!scene_singleton); + //pipeline variants will clear themselves if shader is gone + if (version.is_valid()) { + scene_singleton->volumetric_fog.shader.version_free(version); + } +} + +//////////////////////////////////////////////////////////////////////////////// +// Fog material + +bool RendererSceneRenderRD::FogMaterialData::update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty) { + RendererSceneRenderRD *scene_singleton = (RendererSceneRenderRD *)RendererSceneRenderRD::singleton; + + uniform_set_updated = true; + + return update_parameters_uniform_set(p_parameters, p_uniform_dirty, p_textures_dirty, shader_data->uniforms, shader_data->ubo_offsets.ptr(), shader_data->texture_uniforms, shader_data->default_texture_params, shader_data->ubo_size, uniform_set, scene_singleton->volumetric_fog.shader.version_get_shader(shader_data->version, 0), VolumetricFogShader::FogSet::FOG_SET_MATERIAL); +} + +RendererSceneRenderRD::FogMaterialData::~FogMaterialData() { + free_parameters_uniform_set(uniform_set); +} + +RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_func() { + FogShaderData *shader_data = memnew(FogShaderData); + return shader_data; +} + +RendererStorageRD::ShaderData *RendererSceneRenderRD::_create_fog_shader_funcs() { + return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->_create_fog_shader_func(); +}; + +RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_fog_material_func(FogShaderData *p_shader) { + FogMaterialData *material_data = memnew(FogMaterialData); + material_data->shader_data = p_shader; + material_data->last_frame = false; + //update will happen later anyway so do nothing. + return material_data; +} + +RendererStorageRD::MaterialData *RendererSceneRenderRD::_create_fog_material_funcs(RendererStorageRD::ShaderData *p_shader) { + return static_cast<RendererSceneRenderRD *>(RendererSceneRenderRD::singleton)->_create_fog_material_func(static_cast<FogShaderData *>(p_shader)); +}; + +//////////////////////////////////////////////////////////////////////////////// +// Volumetric Fog + void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { ERR_FAIL_COND(!rb->volumetric_fog); @@ -3468,11 +3760,14 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { RD::get_singleton()->free(rb->volumetric_fog->light_density_map); RD::get_singleton()->free(rb->volumetric_fog->fog_map); - if (rb->volumetric_fog->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { - RD::get_singleton()->free(rb->volumetric_fog->uniform_set); + if (rb->volumetric_fog->fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) { + RD::get_singleton()->free(rb->volumetric_fog->fog_uniform_set); } - if (rb->volumetric_fog->uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set2)) { - RD::get_singleton()->free(rb->volumetric_fog->uniform_set2); + if (rb->volumetric_fog->process_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set)) { + RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set); + } + if (rb->volumetric_fog->process_uniform_set2.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set2)) { + RD::get_singleton()->free(rb->volumetric_fog->process_uniform_set2); } if (rb->volumetric_fog->sdfgi_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->sdfgi_uniform_set)) { RD::get_singleton()->free(rb->volumetric_fog->sdfgi_uniform_set); @@ -3486,11 +3781,30 @@ void RendererSceneRenderRD::_volumetric_fog_erase(RenderBuffers *rb) { rb->volumetric_fog = nullptr; } -void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count) { +Vector3i RendererSceneRenderRD::_point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform) { + Vector3 view_position = p_cam_transform.affine_inverse().xform(p_point); + view_position.z = MIN(view_position.z, -0.01); // Clamp to the front of camera + Vector3 fog_position = Vector3(0, 0, 0); + + view_position.y = -view_position.y; + fog_position.z = -view_position.z / fog_end; + fog_position.x = (view_position.x / (2 * (fog_near_size.x * (1.0 - fog_position.z) + fog_far_size.x * fog_position.z))) + 0.5; + fog_position.y = (view_position.y / (2 * (fog_near_size.y * (1.0 - fog_position.z) + fog_far_size.y * fog_position.z))) + 0.5; + fog_position.z = Math::pow(float(fog_position.z), float(1.0 / volumetric_fog_detail_spread)); + fog_position = fog_position * fog_size - Vector3(0.5, 0.5, 0.5); + + fog_position.x = CLAMP(fog_position.x, 0.0, fog_size.x); + fog_position.y = CLAMP(fog_position.y, 0.0, fog_size.y); + fog_position.z = CLAMP(fog_position.z, 0.0, fog_size.z); + + return Vector3i(fog_position); +} + +void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes) { ERR_FAIL_COND(!is_clustered_enabled()); // can't use volumetric fog without clustered - RenderBuffers *rb = render_buffers_owner.getornull(p_render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_environment); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_environment); float ratio = float(rb->width) / float((rb->width + rb->height) / 2); uint32_t target_width = uint32_t(float(volumetric_fog_size) * ratio); @@ -3509,6 +3823,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e } RENDER_TIMESTAMP(">Volumetric Fog"); + RD::get_singleton()->draw_command_begin_label("Volumetric Fog"); if (env && env->volumetric_fog_enabled && !rb->volumetric_fog) { //required volumetric fog but not existing, create @@ -3526,15 +3841,43 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_FROM_BIT; rb->volumetric_fog->light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_density_map, "Fog light-density map"); tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; rb->volumetric_fog->prev_light_density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->prev_light_density_map, "Fog previous light-density map"); RD::get_singleton()->texture_clear(rb->volumetric_fog->prev_light_density_map, Color(0, 0, 0, 0), 0, 1, 0, 1); tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_SAMPLING_BIT; rb->volumetric_fog->fog_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->fog_map, "Fog map"); + +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + Vector<uint8_t> dm; + dm.resize(target_width * target_height * volumetric_fog_depth * 4); + dm.fill(0); + + rb->volumetric_fog->density_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->density_map, "Fog density map"); + rb->volumetric_fog->light_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_map, "Fog light map"); + rb->volumetric_fog->emissive_map = RD::get_singleton()->storage_buffer_create(dm.size(), dm); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map"); +#else + tf.format = RD::DATA_FORMAT_R32_UINT; + tf.usage_bits = RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_CAN_COPY_TO_BIT; + rb->volumetric_fog->density_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->density_map, "Fog density map"); + RD::get_singleton()->texture_clear(rb->volumetric_fog->density_map, Color(0, 0, 0, 0), 0, 1, 0, 1); + rb->volumetric_fog->light_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->light_map, "Fog light map"); + RD::get_singleton()->texture_clear(rb->volumetric_fog->light_map, Color(0, 0, 0, 0), 0, 1, 0, 1); + rb->volumetric_fog->emissive_map = RD::get_singleton()->texture_create(tf, RD::TextureView()); + RD::get_singleton()->set_resource_name(rb->volumetric_fog->emissive_map, "Fog emissive map"); + RD::get_singleton()->texture_clear(rb->volumetric_fog->emissive_map, Color(0, 0, 0, 0), 0, 1, 0, 1); +#endif Vector<RD::Uniform> uniforms; { @@ -3548,18 +3891,216 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e rb->volumetric_fog->sky_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, sky.sky_shader.default_shader_rd, RendererSceneSkyRD::SKY_SET_FOG); } - //update volumetric fog + if (p_fog_volumes.size() > 0) { + RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog Volumes"); - if (rb->volumetric_fog->uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->uniform_set)) { - //re create uniform set if needed + RENDER_TIMESTAMP("Render Fog Volumes"); + + VolumetricFogShader::VolumeUBO params; + + Vector2 frustum_near_size = p_cam_projection.get_viewport_half_extents(); + Vector2 frustum_far_size = p_cam_projection.get_far_plane_half_extents(); + float z_near = p_cam_projection.get_z_near(); + float z_far = p_cam_projection.get_z_far(); + float fog_end = env->volumetric_fog_length; + + Vector2 fog_far_size = frustum_near_size.lerp(frustum_far_size, (fog_end - z_near) / (z_far - z_near)); + Vector2 fog_near_size; + if (p_cam_projection.is_orthogonal()) { + fog_near_size = fog_far_size; + } else { + fog_near_size = Vector2(); + } + + params.fog_frustum_size_begin[0] = fog_near_size.x; + params.fog_frustum_size_begin[1] = fog_near_size.y; + + params.fog_frustum_size_end[0] = fog_far_size.x; + params.fog_frustum_size_end[1] = fog_far_size.y; + + params.fog_frustum_end = fog_end; + params.z_near = z_near; + params.z_far = z_far; + params.time = time; + + params.fog_volume_size[0] = rb->volumetric_fog->width; + params.fog_volume_size[1] = rb->volumetric_fog->height; + params.fog_volume_size[2] = rb->volumetric_fog->depth; + + params.use_temporal_reprojection = env->volumetric_fog_temporal_reprojection; + params.temporal_frame = RSG::rasterizer->get_frame_number() % VolumetricFog::MAX_TEMPORAL_FRAMES; + params.detail_spread = env->volumetric_fog_detail_spread; + params.temporal_blend = env->volumetric_fog_temporal_reprojection_amount; + + Transform3D to_prev_cam_view = rb->volumetric_fog->prev_cam_transform.affine_inverse() * p_cam_transform; + storage->store_transform(to_prev_cam_view, params.to_prev_view); + storage->store_transform(p_cam_transform, params.transform); + + RD::get_singleton()->buffer_update(volumetric_fog.volume_ubo, 0, sizeof(VolumetricFogShader::VolumeUBO), ¶ms, RD::BARRIER_MASK_COMPUTE); + + if (rb->volumetric_fog->fog_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->fog_uniform_set)) { + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 1; + u.ids.push_back(rb->volumetric_fog->emissive_map); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_UNIFORM_BUFFER; + u.binding = 2; + u.ids.push_back(volumetric_fog.volume_ubo); + uniforms.push_back(u); + } + + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 3; + u.ids.push_back(rb->volumetric_fog->density_map); + uniforms.push_back(u); + } + + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 4; + u.ids.push_back(rb->volumetric_fog->light_map); + uniforms.push_back(u); + } + + rb->volumetric_fog->fog_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS); + } + + RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); + bool any_uses_time = false; + + for (int i = 0; i < (int)p_fog_volumes.size(); i++) { + FogVolumeInstance *fog_volume_instance = fog_volume_instance_owner.get_or_null(p_fog_volumes[i]); + ERR_FAIL_COND(!fog_volume_instance); + RID fog_volume = fog_volume_instance->volume; + + RID fog_material = storage->fog_volume_get_material(fog_volume); + + FogMaterialData *material = nullptr; + if (fog_material.is_valid()) { + material = (FogMaterialData *)storage->material_get_data(fog_material, RendererStorageRD::SHADER_TYPE_FOG); + if (!material || !material->shader_data->valid) { + material = nullptr; + } + } + + if (!material) { + fog_material = volumetric_fog.default_material; + material = (FogMaterialData *)storage->material_get_data(fog_material, RendererStorageRD::SHADER_TYPE_FOG); + } + + ERR_FAIL_COND(!material); + + FogShaderData *shader_data = material->shader_data; + + ERR_FAIL_COND(!shader_data); + + any_uses_time |= shader_data->uses_time; + + Vector3i min = Vector3i(); + Vector3i max = Vector3i(); + Vector3i kernel_size = Vector3i(); + + Vector3 position = fog_volume_instance->transform.get_origin(); + RS::FogVolumeShape volume_type = storage->fog_volume_get_shape(fog_volume); + Vector3 extents = storage->fog_volume_get_extents(fog_volume); + + if (volume_type == RS::FOG_VOLUME_SHAPE_BOX || volume_type == RS::FOG_VOLUME_SHAPE_ELLIPSOID) { + Vector3i points[8]; + points[0] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); + points[1] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); + points[2] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); + points[3] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); + points[4] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); + points[5] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); + points[6] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); + points[7] = _point_get_position_in_froxel_volume(fog_volume_instance->transform.xform(Vector3(-extents.x, -extents.y, -extents.z)), fog_end, fog_near_size, fog_far_size, env->volumetric_fog_detail_spread, Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), p_cam_transform); + + min = Vector3i(int32_t(rb->volumetric_fog->width) - 1, int32_t(rb->volumetric_fog->height) - 1, int32_t(rb->volumetric_fog->depth) - 1); + max = Vector3i(1, 1, 1); + + for (int j = 0; j < 8; j++) { + min = Vector3i(MIN(min.x, points[j].x), MIN(min.y, points[j].y), MIN(min.z, points[j].z)); + max = Vector3i(MAX(max.x, points[j].x), MAX(max.y, points[j].y), MAX(max.z, points[j].z)); + } + + kernel_size = max - min; + } else { + // Volume type global runs on all cells + extents = Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); + min = Vector3i(0, 0, 0); + kernel_size = Vector3i(int32_t(rb->volumetric_fog->width), int32_t(rb->volumetric_fog->height), int32_t(rb->volumetric_fog->depth)); + } + + if (kernel_size.x == 0 || kernel_size.y == 0 || kernel_size.z == 0) { + continue; + } + + volumetric_fog.push_constant.position[0] = position.x; + volumetric_fog.push_constant.position[1] = position.y; + volumetric_fog.push_constant.position[2] = position.z; + volumetric_fog.push_constant.extents[0] = extents.x; + volumetric_fog.push_constant.extents[1] = extents.y; + volumetric_fog.push_constant.extents[2] = extents.z; + volumetric_fog.push_constant.corner[0] = min.x; + volumetric_fog.push_constant.corner[1] = min.y; + volumetric_fog.push_constant.corner[2] = min.z; + volumetric_fog.push_constant.shape = uint32_t(storage->fog_volume_get_shape(fog_volume)); + storage->store_transform(fog_volume_instance->transform.affine_inverse(), volumetric_fog.push_constant.transform); + + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, shader_data->pipeline); + + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->fog_uniform_set, VolumetricFogShader::FogSet::FOG_SET_UNIFORMS); + RD::get_singleton()->compute_list_set_push_constant(compute_list, &volumetric_fog.push_constant, sizeof(VolumetricFogShader::FogPushConstant)); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, volumetric_fog.base_uniform_set, VolumetricFogShader::FogSet::FOG_SET_BASE); + if (material->uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(material->uniform_set)) { // Material may not have a uniform set. + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, material->uniform_set, VolumetricFogShader::FogSet::FOG_SET_MATERIAL); + } + + RD::get_singleton()->compute_list_dispatch_threads(compute_list, kernel_size.x, kernel_size.y, kernel_size.z); + } + if (any_uses_time || env->volumetric_fog_temporal_reprojection) { + RenderingServerDefault::redraw_request(); + } + + RD::get_singleton()->draw_command_end_label(); + + RD::get_singleton()->compute_list_end(); + } + + if (rb->volumetric_fog->process_uniform_set.is_null() || !RD::get_singleton()->uniform_set_is_valid(rb->volumetric_fog->process_uniform_set)) { + //re create uniform set if needed Vector<RD::Uniform> uniforms; + Vector<RD::Uniform> copy_uniforms; { RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); if (shadow_atlas == nullptr || shadow_atlas->depth.is_null()) { u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); } else { @@ -3567,6 +4108,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e } uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3579,6 +4121,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.ids.push_back(storage->texture_rd_get_default(RendererStorageRD::DEFAULT_RD_TEXTURE_BLACK)); } uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3587,6 +4130,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 3; u.ids.push_back(get_omni_light_buffer()); uniforms.push_back(u); + copy_uniforms.push_back(u); } { RD::Uniform u; @@ -3594,6 +4138,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 4; u.ids.push_back(get_spot_light_buffer()); uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3602,6 +4147,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 5; u.ids.push_back(get_directional_light_buffer()); uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3610,6 +4156,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 6; u.ids.push_back(rb->cluster_builder->get_cluster_buffer()); uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3618,6 +4165,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 7; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3626,6 +4174,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 8; u.ids.push_back(rb->volumetric_fog->light_density_map); uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3638,10 +4187,19 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e { RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; + u.binding = 9; + u.ids.push_back(rb->volumetric_fog->prev_light_density_map); + copy_uniforms.push_back(u); + } + + { + RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; u.binding = 10; u.ids.push_back(shadow_sampler); uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3650,6 +4208,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 11; u.ids.push_back(render_buffers_get_voxel_gi_buffer(p_render_buffers)); uniforms.push_back(u); + copy_uniforms.push_back(u); } { @@ -3660,6 +4219,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.ids.push_back(rb->gi.voxel_gi_textures[i]); } uniforms.push_back(u); + copy_uniforms.push_back(u); } { RD::Uniform u; @@ -3667,6 +4227,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 13; u.ids.push_back(storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED)); uniforms.push_back(u); + copy_uniforms.push_back(u); } { RD::Uniform u; @@ -3674,6 +4235,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.binding = 14; u.ids.push_back(volumetric_fog.params_ubo); uniforms.push_back(u); + copy_uniforms.push_back(u); } { RD::Uniform u; @@ -3682,12 +4244,58 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e u.ids.push_back(rb->volumetric_fog->prev_light_density_map); uniforms.push_back(u); } + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 16; + u.ids.push_back(rb->volumetric_fog->density_map); + uniforms.push_back(u); + } + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 17; + u.ids.push_back(rb->volumetric_fog->light_map); + uniforms.push_back(u); + } - rb->volumetric_fog->uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0); + { + RD::Uniform u; +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; +#else + u.uniform_type = RD::UNIFORM_TYPE_IMAGE; +#endif + u.binding = 18; + u.ids.push_back(rb->volumetric_fog->emissive_map); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; + u.binding = 19; + RID radiance_texture = storage->texture_rd_get_default(is_using_radiance_cubemap_array() ? RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK : RendererStorageRD::DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + RID sky_texture = env->sky.is_valid() ? sky.sky_get_radiance_texture_rd(env->sky) : RID(); + u.ids.push_back(sky_texture.is_valid() ? sky_texture : radiance_texture); + uniforms.push_back(u); + } + + rb->volumetric_fog->copy_uniform_set = RD::get_singleton()->uniform_set_create(copy_uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY), 0); + + rb->volumetric_fog->process_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY), 0); SWAP(uniforms.write[7].ids.write[0], uniforms.write[8].ids.write[0]); - rb->volumetric_fog->uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, 0), 0); + rb->volumetric_fog->process_uniform_set2 = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, 0), 0); } bool using_sdfgi = env->volumetric_fog_gi_inject > 0.0001 && env->sdfgi_enabled && (rb->sdfgi != nullptr); @@ -3720,7 +4328,7 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e uniforms.push_back(u); } - rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI), 1); + rb->volumetric_fog->sdfgi_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI), 1); } } @@ -3749,23 +4357,35 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e params.fog_frustum_size_end[0] = fog_far_size.x; params.fog_frustum_size_end[1] = fog_far_size.y; - params.z_near = z_near; + params.ambient_inject = env->volumetric_fog_ambient_inject * env->ambient_light_energy; params.z_far = z_far; params.fog_frustum_end = fog_end; + Color ambient_color = env->ambient_light.to_linear(); + params.ambient_color[0] = ambient_color.r; + params.ambient_color[1] = ambient_color.g; + params.ambient_color[2] = ambient_color.b; + params.sky_contribution = env->ambient_sky_contribution; + params.fog_volume_size[0] = rb->volumetric_fog->width; params.fog_volume_size[1] = rb->volumetric_fog->height; params.fog_volume_size[2] = rb->volumetric_fog->depth; params.directional_light_count = p_directional_light_count; - Color light = env->volumetric_fog_light.to_linear(); - params.light_energy[0] = light.r * env->volumetric_fog_light_energy; - params.light_energy[1] = light.g * env->volumetric_fog_light_energy; - params.light_energy[2] = light.b * env->volumetric_fog_light_energy; + Color emission = env->volumetric_fog_emission.to_linear(); + params.base_emission[0] = emission.r * env->volumetric_fog_emission_energy; + params.base_emission[1] = emission.g * env->volumetric_fog_emission_energy; + params.base_emission[2] = emission.b * env->volumetric_fog_emission_energy; params.base_density = env->volumetric_fog_density; + Color base_scattering = env->volumetric_fog_scattering.to_linear(); + params.base_scattering[0] = base_scattering.r; + params.base_scattering[1] = base_scattering.g; + params.base_scattering[2] = base_scattering.b; + params.phase_g = env->volumetric_fog_anisotropy; + params.detail_spread = env->volumetric_fog_detail_spread; params.gi_inject = env->volumetric_fog_gi_inject; @@ -3805,10 +4425,9 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e params.screen_size[1] = rb->height; } - /* Vector2 dssize = directional_shadow_get_size(); - push_constant.directional_shadow_pixel_size[0] = 1.0 / dssize.x; - push_constant.directional_shadow_pixel_size[1] = 1.0 / dssize.y; -*/ + Basis sky_transform = env->sky_orientation; + sky_transform = sky_transform.inverse() * p_cam_transform.basis; + RendererStorageRD::store_transform_3x3(sky_transform, params.radiance_inverse_xform); RD::get_singleton()->draw_command_begin_label("Render Volumetric Fog"); @@ -3817,33 +4436,32 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e RD::ComputeListID compute_list = RD::get_singleton()->compute_list_begin(); - bool use_filter = volumetric_fog_filter_active; - - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[using_sdfgi ? VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI : VOLUMETRIC_FOG_SHADER_DENSITY]); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[using_sdfgi ? VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI : VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0); if (using_sdfgi) { RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1); } RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); + RD::get_singleton()->compute_list_add_barrier(compute_list); + // Copy fog to history buffer + if (env->volumetric_fog_temporal_reprojection) { + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_COPY]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->copy_uniform_set, 0); + RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); + RD::get_singleton()->compute_list_add_barrier(compute_list); + } RD::get_singleton()->draw_command_end_label(); - RD::get_singleton()->compute_list_end(); - - RD::get_singleton()->texture_copy(rb->volumetric_fog->light_density_map, rb->volumetric_fog->prev_light_density_map, Vector3(0, 0, 0), Vector3(0, 0, 0), Vector3(rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth), 0, 0, 0, 0); - - compute_list = RD::get_singleton()->compute_list_begin(); - - if (use_filter) { + if (volumetric_fog_filter_active) { RD::get_singleton()->draw_command_begin_label("Filter Fog"); RENDER_TIMESTAMP("Filter Fog"); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); - + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0); RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); RD::get_singleton()->compute_list_end(); @@ -3853,11 +4471,8 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e RD::get_singleton()->buffer_update(volumetric_fog.params_ubo, 0, sizeof(VolumetricFogShader::ParamsUBO), ¶ms); compute_list = RD::get_singleton()->compute_list_begin(); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FILTER]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set2, 0); - if (using_sdfgi) { - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->sdfgi_uniform_set, 1); - } + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FILTER]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set2, 0); RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, rb->volumetric_fog->depth); RD::get_singleton()->compute_list_add_barrier(compute_list); @@ -3867,21 +4482,22 @@ void RendererSceneRenderRD::_update_volumetric_fog(RID p_render_buffers, RID p_e RENDER_TIMESTAMP("Integrate Fog"); RD::get_singleton()->draw_command_begin_label("Integrate Fog"); - RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.pipelines[VOLUMETRIC_FOG_SHADER_FOG]); - RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->uniform_set, 0); + RD::get_singleton()->compute_list_bind_compute_pipeline(compute_list, volumetric_fog.process_pipelines[VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_FOG]); + RD::get_singleton()->compute_list_bind_uniform_set(compute_list, rb->volumetric_fog->process_uniform_set, 0); RD::get_singleton()->compute_list_dispatch_threads(compute_list, rb->volumetric_fog->width, rb->volumetric_fog->height, 1); RD::get_singleton()->compute_list_end(RD::BARRIER_MASK_RASTER); RENDER_TIMESTAMP("<Volumetric Fog"); RD::get_singleton()->draw_command_end_label(); + RD::get_singleton()->draw_command_end_label(); rb->volumetric_fog->prev_cam_transform = p_cam_transform; } bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) { if (p_render_data->render_buffers.is_valid()) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); if (rb->sdfgi != nullptr) { return true; } @@ -3892,14 +4508,14 @@ bool RendererSceneRenderRD::_needs_post_prepass_render(RenderDataRD *p_render_da void RendererSceneRenderRD::_post_prepass_render(RenderDataRD *p_render_data, bool p_use_gi) { if (p_render_data->render_buffers.is_valid()) { if (p_use_gi) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); ERR_FAIL_COND(rb == nullptr); if (rb->sdfgi == nullptr) { return; } - RendererSceneEnvironmentRD *env = environment_owner.getornull(p_render_data->environment); - rb->sdfgi->update_probes(env, sky.sky_owner.getornull(env->sky)); + RendererSceneEnvironmentRD *env = environment_owner.get_or_null(p_render_data->environment); + rb->sdfgi->update_probes(env, sky.sky_owner.get_or_null(env->sky)); } } } @@ -3916,7 +4532,7 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool // Render shadows while GI is rendering, due to how barriers are handled, this should happen at the same time if (p_render_data->render_buffers.is_valid() && p_use_gi) { - RenderBuffers *rb = render_buffers_owner.getornull(p_render_data->render_buffers); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_render_data->render_buffers); ERR_FAIL_COND(rb == nullptr); if (rb->sdfgi != nullptr) { rb->sdfgi->store_probes(); @@ -3927,11 +4543,11 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool render_state.shadows.clear(); render_state.directional_shadows.clear(); - Plane camera_plane(p_render_data->cam_transform.origin, -p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z)); + Plane camera_plane(-p_render_data->cam_transform.basis.get_axis(Vector3::AXIS_Z), p_render_data->cam_transform.origin); float lod_distance_multiplier = p_render_data->cam_projection.get_lod_multiplier(); { for (int i = 0; i < render_state.render_shadow_count; i++) { - LightInstance *li = light_instance_owner.getornull(render_state.render_shadows[i].light); + LightInstance *li = light_instance_owner.get_or_null(render_state.render_shadows[i].light); if (storage->light_get_type(li->light) == RS::LIGHT_DIRECTIONAL) { render_state.directional_shadows.push_back(i); @@ -4042,16 +4658,16 @@ void RendererSceneRenderRD::_pre_opaque_render(RenderDataRD *p_render_data, bool } } if (is_volumetric_supported()) { - _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count); + _update_volumetric_fog(p_render_data->render_buffers, p_render_data->environment, p_render_data->cam_projection, p_render_data->cam_transform, p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, render_state.voxel_gi_count, *p_render_data->fog_volumes); } } } -void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) { +void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data, RendererScene::RenderInfo *r_render_info) { // getting this here now so we can direct call a bunch of things more easily RenderBuffers *rb = nullptr; if (p_render_buffers.is_valid()) { - rb = render_buffers_owner.getornull(p_render_buffers); + rb = render_buffers_owner.get_or_null(p_render_buffers); ERR_FAIL_COND(!rb); } @@ -4080,6 +4696,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData render_data.voxel_gi_instances = &p_voxel_gi_instances; render_data.decals = &p_decals; render_data.lightmaps = &p_lightmaps; + render_data.fog_volumes = &p_fog_volumes; render_data.environment = p_environment; render_data.camera_effects = p_camera_effects; render_data.shadow_atlas = p_shadow_atlas; @@ -4089,7 +4706,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData // this should be the same for all cameras.. render_data.lod_distance_multiplier = p_camera_data->main_projection.get_lod_multiplier(); - render_data.lod_camera_plane = Plane(p_camera_data->main_transform.get_origin(), -p_camera_data->main_transform.basis.get_axis(Vector3::AXIS_Z)); + render_data.lod_camera_plane = Plane(-p_camera_data->main_transform.basis.get_axis(Vector3::AXIS_Z), p_camera_data->main_transform.get_origin()); if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_DISABLE_LOD) { render_data.screen_lod_threshold = 0.0; @@ -4133,7 +4750,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData //assign render indices to voxel_gi_instances if (is_dynamic_gi_supported()) { for (uint32_t i = 0; i < (uint32_t)p_voxel_gi_instances.size(); i++) { - RendererSceneGIRD::VoxelGIInstance *voxel_gi_inst = gi.voxel_gi_instance_owner.getornull(p_voxel_gi_instances[i]); + RendererSceneGIRD::VoxelGIInstance *voxel_gi_inst = gi.voxel_gi_instance_owner.get_or_null(p_voxel_gi_instances[i]); if (voxel_gi_inst) { voxel_gi_inst->render_index = i; } @@ -4144,8 +4761,8 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData // render_data.render_buffers == p_render_buffers so we can use our already retrieved rb current_cluster_builder = rb->cluster_builder; } else if (reflection_probe_instance_owner.owns(render_data.reflection_probe)) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(render_data.reflection_probe); - ReflectionAtlas *ra = reflection_atlas_owner.getornull(rpi->atlas); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(render_data.reflection_probe); + ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(rpi->atlas); if (!ra) { ERR_PRINT("reflection probe has no reflection atlas! Bug?"); current_cluster_builder = nullptr; @@ -4182,9 +4799,7 @@ void RendererSceneRenderRD::render_scene(RID p_render_buffers, const CameraData if (p_render_buffers.is_valid()) { /* _debug_draw_cluster(p_render_buffers); - RENDER_TIMESTAMP("Tonemap"); - _render_buffers_post_process_and_tonemap(&render_data); */ @@ -4223,7 +4838,7 @@ void RendererSceneRenderRD::_debug_draw_cluster(RID p_render_buffers) { } void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, int p_pass, const PagedArray<GeometryInstance *> &p_instances, const Plane &p_camera_plane, float p_lod_distance_multiplier, float p_screen_lod_threshold, bool p_open_pass, bool p_close_pass, bool p_clear_region, RendererScene::RenderInfo *p_render_info) { - LightInstance *light_instance = light_instance_owner.getornull(p_light); + LightInstance *light_instance = light_instance_owner.get_or_null(p_light); ERR_FAIL_COND(!light_instance); Rect2i atlas_rect; @@ -4258,10 +4873,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, light_projection = light_instance->shadow_transform[p_pass].camera; light_transform = light_instance->shadow_transform[p_pass].transform; - atlas_rect.position.x = light_instance->directional_rect.position.x; - atlas_rect.position.y = light_instance->directional_rect.position.y; - atlas_rect.size.width = light_instance->directional_rect.size.x; - atlas_rect.size.height = light_instance->directional_rect.size.y; + atlas_rect = light_instance->directional_rect; if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { atlas_rect.size.width /= 2; @@ -4272,8 +4884,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, } else if (p_pass == 2) { atlas_rect.position.y += atlas_rect.size.height; } else if (p_pass == 3) { - atlas_rect.position.x += atlas_rect.size.width; - atlas_rect.position.y += atlas_rect.size.height; + atlas_rect.position += atlas_rect.size; } } else if (storage->light_directional_get_shadow_mode(light_instance->light) == RS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { atlas_rect.size.height /= 2; @@ -4298,7 +4909,7 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, } else { //set from shadow atlas - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); @@ -4382,10 +4993,8 @@ void RendererSceneRenderRD::_render_shadow_pass(RID p_light, RID p_shadow_atlas, _render_shadow_end(); //reblit Rect2 atlas_rect_norm = atlas_rect; - atlas_rect_norm.position.x /= float(atlas_size); - atlas_rect_norm.position.y /= float(atlas_size); - atlas_rect_norm.size.x /= float(atlas_size); - atlas_rect_norm.size.y /= float(atlas_size); + atlas_rect_norm.position /= float(atlas_size); + atlas_rect_norm.size /= float(atlas_size); storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), false); atlas_rect_norm.position += Vector2(dual_paraboloid_offset) * atlas_rect_norm.size; storage->get_effects()->copy_cubemap_to_dp(render_texture, atlas_fb, atlas_rect_norm, atlas_rect.size, light_projection.get_z_near(), light_projection.get_z_far(), true); @@ -4423,7 +5032,7 @@ void RendererSceneRenderRD::render_particle_collider_heightfield(RID p_collider, bool RendererSceneRenderRD::free(RID p_rid) { if (render_buffers_owner.owns(p_rid)) { - RenderBuffers *rb = render_buffers_owner.getornull(p_rid); + RenderBuffers *rb = render_buffers_owner.get_or_null(p_rid); _free_render_buffer_data(rb); memdelete(rb->data); if (rb->sdfgi) { @@ -4446,24 +5055,24 @@ bool RendererSceneRenderRD::free(RID p_rid) { camera_effects_owner.free(p_rid); } else if (reflection_atlas_owner.owns(p_rid)) { reflection_atlas_set_size(p_rid, 0, 0); - ReflectionAtlas *ra = reflection_atlas_owner.getornull(p_rid); + ReflectionAtlas *ra = reflection_atlas_owner.get_or_null(p_rid); if (ra->cluster_builder) { memdelete(ra->cluster_builder); } reflection_atlas_owner.free(p_rid); } else if (reflection_probe_instance_owner.owns(p_rid)) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_rid); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_rid); _free_forward_id(FORWARD_ID_TYPE_REFLECTION_PROBE, rpi->forward_id); reflection_probe_release_atlas_index(p_rid); reflection_probe_instance_owner.free(p_rid); } else if (decal_instance_owner.owns(p_rid)) { - DecalInstance *di = decal_instance_owner.getornull(p_rid); + DecalInstance *di = decal_instance_owner.get_or_null(p_rid); _free_forward_id(FORWARD_ID_TYPE_DECAL, di->forward_id); decal_instance_owner.free(p_rid); } else if (lightmap_instance_owner.owns(p_rid)) { lightmap_instance_owner.free(p_rid); } else if (gi.voxel_gi_instance_owner.owns(p_rid)) { - RendererSceneGIRD::VoxelGIInstance *voxel_gi = gi.voxel_gi_instance_owner.getornull(p_rid); + RendererSceneGIRD::VoxelGIInstance *voxel_gi = gi.voxel_gi_instance_owner.get_or_null(p_rid); if (voxel_gi->texture.is_valid()) { RD::get_singleton()->free(voxel_gi->texture); RD::get_singleton()->free(voxel_gi->write_buffer); @@ -4479,11 +5088,11 @@ bool RendererSceneRenderRD::free(RID p_rid) { sky.update_dirty_skys(); sky.free_sky(p_rid); } else if (light_instance_owner.owns(p_rid)) { - LightInstance *light_instance = light_instance_owner.getornull(p_rid); + LightInstance *light_instance = light_instance_owner.get_or_null(p_rid); //remove from shadow atlases.. for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(E->get()); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(E->get()); ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); uint32_t key = shadow_atlas->shadow_owners[p_rid]; uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; @@ -4507,7 +5116,8 @@ bool RendererSceneRenderRD::free(RID p_rid) { } else if (shadow_atlas_owner.owns(p_rid)) { shadow_atlas_set_size(p_rid, 0); shadow_atlas_owner.free(p_rid); - + } else if (fog_volume_instance_owner.owns(p_rid)) { + fog_volume_instance_owner.free(p_rid); } else { return false; } @@ -4748,18 +5358,124 @@ void RendererSceneRenderRD::init() { } if (is_volumetric_supported()) { - String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n"; - Vector<String> volumetric_fog_modes; - volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n"); - volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n"); - volumetric_fog_modes.push_back("\n#define MODE_FILTER\n"); - volumetric_fog_modes.push_back("\n#define MODE_FOG\n"); - volumetric_fog.shader.initialize(volumetric_fog_modes, defines); - volumetric_fog.shader_version = volumetric_fog.shader.version_create(); - for (int i = 0; i < VOLUMETRIC_FOG_SHADER_MAX; i++) { - volumetric_fog.pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.shader.version_get_shader(volumetric_fog.shader_version, i)); + { + // Initialize local fog shader + Vector<String> volumetric_fog_modes; + volumetric_fog_modes.push_back(""); + volumetric_fog.shader.initialize(volumetric_fog_modes); + + storage->shader_set_data_request_function(RendererStorageRD::SHADER_TYPE_FOG, _create_fog_shader_funcs); + storage->material_set_data_request_function(RendererStorageRD::SHADER_TYPE_FOG, _create_fog_material_funcs); + volumetric_fog.volume_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::VolumeUBO)); + } + + { + ShaderCompilerRD::DefaultIdentifierActions actions; + + actions.renames["TIME"] = "scene_params.time"; + actions.renames["PI"] = _MKSTR(Math_PI); + actions.renames["TAU"] = _MKSTR(Math_TAU); + actions.renames["E"] = _MKSTR(Math_E); + actions.renames["WORLD_POSITION"] = "world.xyz"; + actions.renames["OBJECT_POSITION"] = "params.position"; + actions.renames["UVW"] = "uvw"; + actions.renames["EXTENTS"] = "params.extents"; + actions.renames["ALBEDO"] = "albedo"; + actions.renames["DENSITY"] = "density"; + actions.renames["EMISSION"] = "emission"; + actions.renames["SDF"] = "sdf"; + + actions.usage_defines["SDF"] = "#define SDF_USED\n"; + actions.usage_defines["DENSITY"] = "#define DENSITY_USED\n"; + actions.usage_defines["ALBEDO"] = "#define ALBEDO_USED\n"; + actions.usage_defines["EMISSION"] = "#define EMISSION_USED\n"; + + actions.sampler_array_name = "material_samplers"; + actions.base_texture_binding_index = 1; + actions.texture_layout_set = VolumetricFogShader::FogSet::FOG_SET_MATERIAL; + actions.base_uniform_string = "material."; + + actions.default_filter = ShaderLanguage::FILTER_LINEAR_MIPMAP; + actions.default_repeat = ShaderLanguage::REPEAT_DISABLE; + actions.global_buffer_array_variable = "global_variables.data"; + + volumetric_fog.compiler.initialize(actions); + } + + { + // default material and shader for fog shader + volumetric_fog.default_shader = storage->shader_allocate(); + storage->shader_initialize(volumetric_fog.default_shader); + storage->shader_set_code(volumetric_fog.default_shader, R"( +// Default fog shader. + +shader_type fog; + +void fog() { + DENSITY = 1.0; + ALBEDO = vec3(1.0); +} +)"); + volumetric_fog.default_material = storage->material_allocate(); + storage->material_initialize(volumetric_fog.default_material); + storage->material_set_shader(volumetric_fog.default_material, volumetric_fog.default_shader); + + FogMaterialData *md = (FogMaterialData *)storage->material_get_data(volumetric_fog.default_material, RendererStorageRD::SHADER_TYPE_FOG); + volumetric_fog.default_shader_rd = volumetric_fog.shader.version_get_shader(md->shader_data->version, 0); + + Vector<RD::Uniform> uniforms; + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_SAMPLER; + u.binding = 1; + u.ids.resize(12); + RID *ids_ptr = u.ids.ptrw(); + ids_ptr[0] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[1] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[2] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[3] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[4] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[5] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED); + ids_ptr[6] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[7] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[8] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[9] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[10] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + ids_ptr[11] = storage->sampler_rd_get_default(RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC, RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED); + uniforms.push_back(u); + } + + { + RD::Uniform u; + u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; + u.binding = 2; + u.ids.push_back(storage->global_variables_get_storage_buffer()); + uniforms.push_back(u); + } + + volumetric_fog.base_uniform_set = RD::get_singleton()->uniform_set_create(uniforms, volumetric_fog.default_shader_rd, VolumetricFogShader::FogSet::FOG_SET_BASE); + } + { + String defines = "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(cluster.max_directional_lights) + "\n"; + defines += "\n#define MAX_SKY_LOD " + itos(get_roughness_layers() - 1) + ".0\n"; + if (is_using_radiance_cubemap_array()) { + defines += "\n#define USE_RADIANCE_CUBEMAP_ARRAY \n"; + } + Vector<String> volumetric_fog_modes; + volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n"); + volumetric_fog_modes.push_back("\n#define MODE_DENSITY\n#define ENABLE_SDFGI\n"); + volumetric_fog_modes.push_back("\n#define MODE_FILTER\n"); + volumetric_fog_modes.push_back("\n#define MODE_FOG\n"); + volumetric_fog_modes.push_back("\n#define MODE_COPY\n"); + + volumetric_fog.process_shader.initialize(volumetric_fog_modes, defines); + volumetric_fog.process_shader_version = volumetric_fog.process_shader.version_create(); + for (int i = 0; i < VolumetricFogShader::VOLUMETRIC_FOG_PROCESS_SHADER_MAX; i++) { + volumetric_fog.process_pipelines[i] = RD::get_singleton()->compute_pipeline_create(volumetric_fog.process_shader.version_get_shader(volumetric_fog.process_shader_version, i)); + } + volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO)); } - volumetric_fog.params_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(VolumetricFogShader::ParamsUBO)); } { @@ -4800,8 +5516,8 @@ void RendererSceneRenderRD::init() { } RendererSceneRenderRD::~RendererSceneRenderRD() { - for (Map<int, ShadowCubemap>::Element *E = shadow_cubemaps.front(); E; E = E->next()) { - RD::get_singleton()->free(E->get().cubemap); + for (const KeyValue<int, ShadowCubemap> &E : shadow_cubemaps) { + RD::get_singleton()->free(E.value.cubemap); } if (sky.sky_scene_state.uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky.sky_scene_state.uniform_set)) { @@ -4810,9 +5526,14 @@ RendererSceneRenderRD::~RendererSceneRenderRD() { if (is_dynamic_gi_supported()) { gi.free(); + } - volumetric_fog.shader.version_free(volumetric_fog.shader_version); + if (is_volumetric_supported()) { + volumetric_fog.process_shader.version_free(volumetric_fog.process_shader_version); + RD::get_singleton()->free(volumetric_fog.volume_ubo); RD::get_singleton()->free(volumetric_fog.params_ubo); + storage->free(volumetric_fog.default_shader); + storage->free(volumetric_fog.default_material); } RendererSceneSkyRD::SkyMaterialData *md = (RendererSceneSkyRD::SkyMaterialData *)storage->material_get_data(sky.sky_shader.default_material, RendererStorageRD::SHADER_TYPE_SKY); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.h b/servers/rendering/renderer_rd/renderer_scene_render_rd.h index eb61af517a..98ab1a2c3c 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.h @@ -40,6 +40,7 @@ #include "servers/rendering/renderer_rd/renderer_scene_sky_rd.h" #include "servers/rendering/renderer_rd/renderer_storage_rd.h" #include "servers/rendering/renderer_rd/shaders/volumetric_fog.glsl.gen.h" +#include "servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl.gen.h" #include "servers/rendering/renderer_scene.h" #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_device.h" @@ -64,6 +65,7 @@ struct RenderDataRD { const PagedArray<RID> *voxel_gi_instances = nullptr; const PagedArray<RID> *decals = nullptr; const PagedArray<RID> *lightmaps = nullptr; + const PagedArray<RID> *fog_volumes = nullptr; RID environment = RID(); RID camera_effects = RID(); RID shadow_atlas = RID(); @@ -149,7 +151,7 @@ protected: RendererSceneEnvironmentRD *get_environment(RID p_environment) { if (p_environment.is_valid()) { - return environment_owner.getornull(p_environment); + return environment_owner.get_or_null(p_environment); } else { return nullptr; } @@ -393,6 +395,16 @@ private: mutable RID_Owner<LightInstance> light_instance_owner; + /* FOG VOLUMES */ + + struct FogVolumeInstance { + RID volume; + Transform3D transform; + bool active = false; + }; + + mutable RID_Owner<FogVolumeInstance> fog_volume_instance_owner; + /* ENVIRONMENT */ RS::EnvironmentSSAOQuality ssao_quality = RS::ENV_SSAO_QUALITY_MEDIUM; @@ -444,7 +456,11 @@ private: struct RenderBuffers { RenderBufferData *data = nullptr; - int width = 0, height = 0; + int internal_width = 0; + int internal_height = 0; + int width = 0; + int height = 0; + float fsr_sharpness = 0.2f; RS::ViewportMSAA msaa = RS::VIEWPORT_MSAA_DISABLED; RS::ViewportScreenSpaceAA screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED; bool use_debanding = false; @@ -454,9 +470,12 @@ private: uint64_t auto_exposure_version = 1; - RID texture; //main texture for rendering to, must be filled after done rendering + RID sss_texture; //texture for sss. This needs to be a different resolution than blur[0] + RID internal_texture; //main texture for rendering to, must be filled after done rendering + RID texture; //upscaled version of main texture (This uses the same resource as internal_texture if there is no upscaling) RID depth_texture; //main depth texture RID texture_fb; // framebuffer for the main texture, ONLY USED FOR MOBILE RENDERER POST EFFECTS, DO NOT USE FOR RENDERING 3D!!! + RID upscale_texture; //used when upscaling internal_texture (This uses the same resource as internal_texture if there is no upscaling) RendererSceneGIRD::SDFGI *sdfgi = nullptr; VolumetricFog *volumetric_fog = nullptr; @@ -718,10 +737,15 @@ private: RID light_density_map; RID prev_light_density_map; - RID fog_map; - RID uniform_set; - RID uniform_set2; + RID density_map; + RID light_map; + RID emissive_map; + + RID fog_uniform_set; + RID copy_uniform_set; + RID process_uniform_set; + RID process_uniform_set2; RID sdfgi_uniform_set; RID sky_uniform_set; @@ -730,30 +754,91 @@ private: Transform3D prev_cam_transform; }; - enum { - VOLUMETRIC_FOG_SHADER_DENSITY, - VOLUMETRIC_FOG_SHADER_DENSITY_WITH_SDFGI, - VOLUMETRIC_FOG_SHADER_FILTER, - VOLUMETRIC_FOG_SHADER_FOG, - VOLUMETRIC_FOG_SHADER_MAX, - }; - struct VolumetricFogShader { - struct ParamsUBO { + enum FogSet { + FOG_SET_BASE, + FOG_SET_UNIFORMS, + FOG_SET_MATERIAL, + FOG_SET_MAX, + }; + + struct FogPushConstant { + float position[3]; + float pad; + + float extents[3]; + float pad2; + + int32_t corner[3]; + uint32_t shape; + + float transform[16]; + }; + + struct VolumeUBO { float fog_frustum_size_begin[2]; float fog_frustum_size_end[2]; float fog_frustum_end; float z_near; float z_far; + float time; + + int32_t fog_volume_size[3]; + uint32_t directional_light_count; + + uint32_t use_temporal_reprojection; + uint32_t temporal_frame; + float detail_spread; + float temporal_blend; + + float to_prev_view[16]; + float transform[16]; + }; + + ShaderCompilerRD compiler; + VolumetricFogShaderRD shader; + FogPushConstant push_constant; + RID volume_ubo; + + RID default_shader; + RID default_material; + RID default_shader_rd; + + RID base_uniform_set; + + RID params_ubo; + + enum { + VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY, + VOLUMETRIC_FOG_PROCESS_SHADER_DENSITY_WITH_SDFGI, + VOLUMETRIC_FOG_PROCESS_SHADER_FILTER, + VOLUMETRIC_FOG_PROCESS_SHADER_FOG, + VOLUMETRIC_FOG_PROCESS_SHADER_COPY, + VOLUMETRIC_FOG_PROCESS_SHADER_MAX, + }; + + struct ParamsUBO { + float fog_frustum_size_begin[2]; + float fog_frustum_size_end[2]; + + float fog_frustum_end; + float ambient_inject; + float z_far; uint32_t filter_axis; + float ambient_color[3]; + float sky_contribution; + int32_t fog_volume_size[3]; uint32_t directional_light_count; - float light_energy[3]; + float base_emission[3]; float base_density; + float base_scattering[3]; + float phase_g; + float detail_spread; float gi_inject; uint32_t max_voxel_gi_instances; @@ -770,13 +855,13 @@ private: float cam_rotation[12]; float to_prev_view[16]; + float radiance_inverse_xform[12]; }; - VolumetricFogShaderRD shader; + VolumetricFogProcessShaderRD process_shader; - RID params_ubo; - RID shader_version; - RID pipelines[VOLUMETRIC_FOG_SHADER_MAX]; + RID process_shader_version; + RID process_pipelines[VOLUMETRIC_FOG_PROCESS_SHADER_MAX]; } volumetric_fog; @@ -784,8 +869,57 @@ private: uint32_t volumetric_fog_size = 128; bool volumetric_fog_filter_active = true; + Vector3i _point_get_position_in_froxel_volume(const Vector3 &p_point, float fog_end, const Vector2 &fog_near_size, const Vector2 &fog_far_size, float volumetric_fog_detail_spread, const Vector3 &fog_size, const Transform3D &p_cam_transform); void _volumetric_fog_erase(RenderBuffers *rb); - void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count); + void _update_volumetric_fog(RID p_render_buffers, RID p_environment, const CameraMatrix &p_cam_projection, const Transform3D &p_cam_transform, RID p_shadow_atlas, int p_directional_light_count, bool p_use_directional_shadows, int p_positional_light_count, int p_voxel_gi_count, const PagedArray<RID> &p_fog_volumes); + + struct FogShaderData : public RendererStorageRD::ShaderData { + bool valid; + RID version; + + RID pipeline; + Map<StringName, ShaderLanguage::ShaderNode::Uniform> uniforms; + Vector<ShaderCompilerRD::GeneratedCode::Texture> texture_uniforms; + + Vector<uint32_t> ubo_offsets; + uint32_t ubo_size; + + String path; + String code; + Map<StringName, Map<int, RID>> default_texture_params; + + bool uses_time; + + virtual void set_code(const String &p_Code); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); + virtual void get_param_list(List<PropertyInfo> *p_param_list) const; + virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; + virtual bool is_param_texture(const StringName &p_param) const; + virtual bool is_animated() const; + virtual bool casts_shadows() const; + virtual Variant get_default_parameter(const StringName &p_parameter) const; + virtual RS::ShaderNativeSourceCode get_native_source_code() const; + FogShaderData(); + virtual ~FogShaderData(); + }; + + struct FogMaterialData : public RendererStorageRD::MaterialData { + uint64_t last_frame; + FogShaderData *shader_data; + RID uniform_set; + bool uniform_set_updated; + + virtual void set_render_priority(int p_priority) {} + virtual void set_next_pass(RID p_pass) {} + virtual bool update_parameters(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty); + virtual ~FogMaterialData(); + }; + + RendererStorageRD::ShaderData *_create_fog_shader_func(); + static RendererStorageRD::ShaderData *_create_fog_shader_funcs(); + + RendererStorageRD::MaterialData *_create_fog_material_func(FogShaderData *p_shader); + static RendererStorageRD::MaterialData *_create_fog_material_funcs(RendererStorageRD::ShaderData *p_shader); RID shadow_sampler; @@ -814,19 +948,19 @@ public: virtual void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) override; virtual bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) override; _FORCE_INLINE_ bool shadow_atlas_owns_light_instance(RID p_atlas, RID p_light_intance) { - ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas); + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND_V(!atlas, false); return atlas->shadow_owners.has(p_light_intance); } _FORCE_INLINE_ RID shadow_atlas_get_texture(RID p_atlas) { - ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas); + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND_V(!atlas, RID()); return atlas->depth; } _FORCE_INLINE_ Size2i shadow_atlas_get_size(RID p_atlas) { - ShadowAtlas *atlas = shadow_atlas_owner.getornull(p_atlas); + ShadowAtlas *atlas = shadow_atlas_owner.get_or_null(p_atlas); ERR_FAIL_COND_V(!atlas, Size2i()); return Size2(atlas->size, atlas->size); } @@ -873,7 +1007,7 @@ public: virtual void environment_set_bg_color(RID p_env, const Color &p_color) override; virtual void environment_set_bg_energy(RID p_env, float p_energy) override; virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) override; - virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) override; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) override; virtual RS::EnvironmentBG environment_get_background(RID p_env) const override; RID environment_get_sky(RID p_env) const; @@ -887,7 +1021,6 @@ public: float environment_get_ambient_light_energy(RID p_env) const; float environment_get_ambient_sky_contribution(RID p_env) const; RS::EnvironmentReflectionSource environment_get_reflection_source(RID p_env) const; - Color environment_get_ao_color(RID p_env) const; virtual bool is_environment(RID p_env) const override; @@ -905,7 +1038,7 @@ public: float environment_get_fog_height_density(RID p_env) const; float environment_get_fog_aerial_perspective(RID p_env) const; - virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) override; + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) override; virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) override; virtual void environment_set_volumetric_fog_filter_active(bool p_enable) override; @@ -932,6 +1065,8 @@ public: virtual Ref<Image> environment_bake_panorama(RID p_env, bool p_bake_irradiance, const Size2i &p_size) override; + /* CAMERA EFFECTS */ + virtual RID camera_effects_allocate() override; virtual void camera_effects_initialize(RID p_rid) override; @@ -942,11 +1077,13 @@ public: virtual void camera_effects_set_custom_exposure(RID p_camera_effects, bool p_enable, float p_exposure) override; bool camera_effects_uses_dof(RID p_camera_effects) { - CameraEffects *camfx = camera_effects_owner.getornull(p_camera_effects); + CameraEffects *camfx = camera_effects_owner.get_or_null(p_camera_effects); return camfx && (camfx->dof_blur_near_enabled || camfx->dof_blur_far_enabled) && camfx->dof_blur_amount > 0.0; } + /* LIGHT INSTANCE API */ + virtual RID light_instance_create(RID p_light) override; virtual void light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) override; virtual void light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) override; @@ -954,18 +1091,18 @@ public: virtual void light_instance_mark_visible(RID p_light_instance) override; _FORCE_INLINE_ RID light_instance_get_base_light(RID p_light_instance) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->light; } _FORCE_INLINE_ Transform3D light_instance_get_base_transform(RID p_light_instance) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->transform; } _FORCE_INLINE_ Rect2 light_instance_get_shadow_atlas_rect(RID p_light_instance, RID p_shadow_atlas, Vector2i &r_omni_offset) { - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - LightInstance *li = light_instance_owner.getornull(p_light_instance); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); uint32_t key = shadow_atlas->shadow_owners[li->self]; uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; @@ -1000,16 +1137,16 @@ public: } _FORCE_INLINE_ CameraMatrix light_instance_get_shadow_camera(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].camera; } _FORCE_INLINE_ float light_instance_get_shadow_texel_size(RID p_light_instance, RID p_shadow_atlas) { #ifdef DEBUG_ENABLED - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); ERR_FAIL_COND_V(!li->shadow_atlases.has(p_shadow_atlas), 0); #endif - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get_or_null(p_shadow_atlas); ERR_FAIL_COND_V(!shadow_atlas, 0); #ifdef DEBUG_ENABLED ERR_FAIL_COND_V(!shadow_atlas->shadow_owners.has(p_light_instance), 0); @@ -1027,68 +1164,76 @@ public: _FORCE_INLINE_ Transform3D light_instance_get_shadow_transform(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].transform; } _FORCE_INLINE_ float light_instance_get_shadow_bias_scale(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].bias_scale; } _FORCE_INLINE_ float light_instance_get_shadow_range(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].farplane; } _FORCE_INLINE_ float light_instance_get_shadow_range_begin(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].range_begin; } _FORCE_INLINE_ Vector2 light_instance_get_shadow_uv_scale(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].uv_scale; } _FORCE_INLINE_ Rect2 light_instance_get_directional_shadow_atlas_rect(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].atlas_rect; } _FORCE_INLINE_ float light_instance_get_directional_shadow_split(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].split; } _FORCE_INLINE_ float light_instance_get_directional_shadow_texel_size(RID p_light_instance, int p_index) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->shadow_transform[p_index].shadow_texel_size; } _FORCE_INLINE_ void light_instance_set_render_pass(RID p_light_instance, uint64_t p_pass) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); li->last_pass = p_pass; } _FORCE_INLINE_ uint64_t light_instance_get_render_pass(RID p_light_instance) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->last_pass; } _FORCE_INLINE_ ForwardID light_instance_get_forward_id(RID p_light_instance) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->forward_id; } _FORCE_INLINE_ RS::LightType light_instance_get_type(RID p_light_instance) { - LightInstance *li = light_instance_owner.getornull(p_light_instance); + LightInstance *li = light_instance_owner.get_or_null(p_light_instance); return li->light_type; } + /* FOG VOLUMES */ + + virtual RID fog_volume_instance_create(RID p_fog_volume) override; + virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) override; + virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) override; + virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const override; + virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const override; + virtual RID reflection_atlas_create() override; virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) override; virtual int reflection_atlas_get_size(RID p_ref_atlas) const override; _FORCE_INLINE_ RID reflection_atlas_get_texture(RID p_ref_atlas) { - ReflectionAtlas *atlas = reflection_atlas_owner.getornull(p_ref_atlas); + ReflectionAtlas *atlas = reflection_atlas_owner.get_or_null(p_ref_atlas); ERR_FAIL_COND_V(!atlas, RID()); return atlas->reflection; } @@ -1107,41 +1252,41 @@ public: RID reflection_probe_instance_get_depth_framebuffer(RID p_instance, int p_index); _FORCE_INLINE_ RID reflection_probe_instance_get_probe(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, RID()); return rpi->probe; } _FORCE_INLINE_ ForwardID reflection_probe_instance_get_forward_id(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, 0); return rpi->forward_id; } _FORCE_INLINE_ void reflection_probe_instance_set_render_pass(RID p_instance, uint32_t p_render_pass) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!rpi); rpi->last_pass = p_render_pass; } _FORCE_INLINE_ uint32_t reflection_probe_instance_get_render_pass(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, 0); return rpi->last_pass; } _FORCE_INLINE_ Transform3D reflection_probe_instance_get_transform(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, Transform3D()); return rpi->transform; } _FORCE_INLINE_ int reflection_probe_instance_get_atlas_index(RID p_instance) { - ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!rpi, -1); return rpi->atlas_index; @@ -1151,32 +1296,32 @@ public: virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override; _FORCE_INLINE_ RID decal_instance_get_base(RID p_decal) const { - DecalInstance *decal = decal_instance_owner.getornull(p_decal); + DecalInstance *decal = decal_instance_owner.get_or_null(p_decal); return decal->decal; } _FORCE_INLINE_ ForwardID decal_instance_get_forward_id(RID p_decal) const { - DecalInstance *decal = decal_instance_owner.getornull(p_decal); + DecalInstance *decal = decal_instance_owner.get_or_null(p_decal); return decal->forward_id; } _FORCE_INLINE_ Transform3D decal_instance_get_transform(RID p_decal) const { - DecalInstance *decal = decal_instance_owner.getornull(p_decal); + DecalInstance *decal = decal_instance_owner.get_or_null(p_decal); return decal->transform; } virtual RID lightmap_instance_create(RID p_lightmap) override; virtual void lightmap_instance_set_transform(RID p_lightmap, const Transform3D &p_transform) override; _FORCE_INLINE_ bool lightmap_instance_is_valid(RID p_lightmap_instance) { - return lightmap_instance_owner.getornull(p_lightmap_instance) != nullptr; + return lightmap_instance_owner.get_or_null(p_lightmap_instance) != nullptr; } _FORCE_INLINE_ RID lightmap_instance_get_lightmap(RID p_lightmap_instance) { - LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); + LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance); return li->lightmap; } _FORCE_INLINE_ Transform3D lightmap_instance_get_transform(RID p_lightmap_instance) { - LightmapInstance *li = lightmap_instance_owner.getornull(p_lightmap_instance); + LightmapInstance *li = lightmap_instance_owner.get_or_null(p_lightmap_instance); return li->transform; } @@ -1194,9 +1339,10 @@ public: virtual RD::DataFormat _render_buffers_get_color_format(); virtual bool _render_buffers_can_be_storage(); virtual RID render_buffers_create() override; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) override; virtual void gi_set_use_half_resolution(bool p_enable) override; + RID render_buffers_get_depth_texture(RID p_render_buffers); RID render_buffers_get_ao_texture(RID p_render_buffers); RID render_buffers_get_back_buffer_texture(RID p_render_buffers); RID render_buffers_get_back_depth_texture(RID p_render_buffers); @@ -1224,7 +1370,9 @@ public: float render_buffers_get_volumetric_fog_end(RID p_render_buffers); float render_buffers_get_volumetric_fog_detail_spread(RID p_render_buffers); - virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; + virtual void update_uniform_sets(){}; + + virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) override; virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) override; diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp index c388da755c..a9c39fb937 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.cpp @@ -137,47 +137,56 @@ void RendererSceneSkyRD::SkyShaderData::set_code(const String &p_code) { valid = true; } -void RendererSceneSkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererSceneSkyRD::SkyShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { if (!p_texture.is_valid()) { - default_texture_params.erase(p_name); + if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { + default_texture_params[p_name].erase(p_index); + + if (default_texture_params[p_name].is_empty()) { + default_texture_params.erase(p_name); + } + } } else { - default_texture_params[p_name] = p_texture; + if (!default_texture_params.has(p_name)) { + default_texture_params[p_name] = Map<int, RID>(); + } + default_texture_params[p_name][p_index] = p_texture; } } void RendererSceneSkyRD::SkyShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); + if (E.value.texture_order >= 0) { + order[E.value.texture_order + 100000] = E.key; } else { - order[E->get().order] = E->key(); + order[E.value.order] = E.key; } } - for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); - pi.name = E->get(); + for (const KeyValue<int, StringName> &E : order) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); + pi.name = E.value; p_param_list->push_back(pi); } } void RendererSceneSkyRD::SkyShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } RendererStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E->get()); - p.info.name = E->key(); //supply name - p.index = E->get().instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p.info = ShaderLanguage::uniform_to_property_info(E.value); + p.info.name = E.key; //supply name + p.index = E.value.instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -202,7 +211,7 @@ Variant RendererSceneSkyRD::SkyShaderData::get_default_parameter(const StringNam if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } @@ -292,7 +301,12 @@ void RendererSceneSkyRD::_render_sky(RD::DrawListID p_list, float p_time, RID p_ RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_uniform_set, 1); } RD::get_singleton()->draw_list_bind_uniform_set(draw_list, p_texture_set, 2); - RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3); + // Fog uniform set can be invalidated before drawing, so validate at draw time + if (sky_scene_state.fog_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(sky_scene_state.fog_uniform_set)) { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.fog_uniform_set, 3); + } else { + RD::get_singleton()->draw_list_bind_uniform_set(draw_list, sky_scene_state.default_fog_uniform_set, 3); + } } RD::get_singleton()->draw_list_bind_index_array(draw_list, index_array); @@ -1036,11 +1050,7 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b SkyShaderData *shader_data = nullptr; - RS::EnvironmentBG background = p_env->background; - - if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { - // !BAS! Possibly silently fail here, we now get error spam when you select sky as the background but haven't setup the sky yet. - ERR_FAIL_COND(!sky); + if (sky) { sky_material = sky_get_material(p_env->sky); if (sky_material.is_valid()) { @@ -1060,9 +1070,7 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b shader_data = material->shader_data; ERR_FAIL_COND(!shader_data); - } - if (sky) { // Invalidate supbass buffers if screen size changes if (sky->screen_size != p_screen_size) { sky->screen_size = p_screen_size; @@ -1171,14 +1179,8 @@ void RendererSceneSkyRD::setup(RendererSceneEnvironmentRD *p_env, RID p_render_b } else { sky_scene_state.ubo.volumetric_fog_detail_spread = 1.0; } - } - RID fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers); - - if (fog_uniform_set != RID()) { - sky_scene_state.fog_uniform_set = fog_uniform_set; - } else { - sky_scene_state.fog_uniform_set = sky_scene_state.default_fog_uniform_set; + sky_scene_state.fog_uniform_set = p_scene_render->render_buffers_get_volumetric_fog_sky_uniform_set(p_render_buffers); } } @@ -1371,7 +1373,6 @@ void RendererSceneSkyRD::draw(RendererSceneEnvironmentRD *p_env, bool p_can_cont ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); Sky *sky = get_sky(p_env->sky); - ERR_FAIL_COND(!sky); SkyMaterialData *material = nullptr; RID sky_material; @@ -1483,27 +1484,17 @@ void RendererSceneSkyRD::update_res_buffers(RendererSceneEnvironmentRD *p_env, u SkyMaterialData *material = nullptr; RID sky_material; - RS::EnvironmentBG background = p_env->background; + sky_material = sky_get_material(p_env->sky); - if (!(background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) || sky) { - ERR_FAIL_COND(!sky); - sky_material = sky_get_material(p_env->sky); - - if (sky_material.is_valid()) { - material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); - if (!material || !material->shader_data->valid) { - material = nullptr; - } - } - - if (!material) { - sky_material = sky_shader.default_material; - material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); + if (sky_material.is_valid()) { + material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); + if (!material || !material->shader_data->valid) { + material = nullptr; } } - if (background == RS::ENV_BG_CLEAR_COLOR || background == RS::ENV_BG_COLOR) { - sky_material = sky_scene_state.fog_material; + if (!material) { + sky_material = sky_shader.default_material; material = (SkyMaterialData *)storage->material_get_data(sky_material, RendererStorageRD::SHADER_TYPE_SKY); } @@ -1572,7 +1563,6 @@ void RendererSceneSkyRD::draw(RD::DrawListID p_draw_list, RendererSceneEnvironme ERR_FAIL_COND(p_view_count > RendererSceneRender::MAX_RENDER_VIEWS); Sky *sky = get_sky(p_env->sky); - ERR_FAIL_COND(!sky); SkyMaterialData *material = nullptr; RID sky_material; @@ -1772,7 +1762,7 @@ void RendererSceneSkyRD::initialize_sky_rid(RID p_rid) { } RendererSceneSkyRD::Sky *RendererSceneSkyRD::get_sky(RID p_sky) const { - return sky_owner.getornull(p_sky); + return sky_owner.get_or_null(p_sky); } void RendererSceneSkyRD::free_sky(RID p_sky) { diff --git a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h index 7f563c9bc4..8689395bea 100644 --- a/servers/rendering/renderer_rd/renderer_scene_sky_rd.h +++ b/servers/rendering/renderer_rd/renderer_scene_sky_rd.h @@ -118,7 +118,7 @@ private: String path; String code; - Map<StringName, RID> default_texture_params; + Map<StringName, Map<int, RID>> default_texture_params; bool uses_time; bool uses_position; @@ -127,7 +127,7 @@ private: bool uses_light; virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.cpp b/servers/rendering/renderer_rd/renderer_storage_rd.cpp index ec0d25376f..04acc871b4 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_storage_rd.cpp @@ -842,7 +842,7 @@ void RendererStorageRD::texture_3d_initialize(RID p_texture, Image::Format p_for } void RendererStorageRD::texture_proxy_initialize(RID p_texture, RID p_base) { - Texture *tex = texture_owner.getornull(p_base); + Texture *tex = texture_owner.get_or_null(p_base); ERR_FAIL_COND(!tex); Texture proxy_tex = *tex; @@ -865,7 +865,7 @@ void RendererStorageRD::texture_proxy_initialize(RID p_texture, RID p_base) { void RendererStorageRD::_texture_2d_update(RID p_texture, const Ref<Image> &p_image, int p_layer, bool p_immediate) { ERR_FAIL_COND(p_image.is_null() || p_image->is_empty()); - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->is_render_target); ERR_FAIL_COND(p_image->get_width() != tex->width || p_image->get_height() != tex->height); @@ -889,7 +889,7 @@ void RendererStorageRD::texture_2d_update(RID p_texture, const Ref<Image> &p_ima } void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image>> &p_data) { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->type != Texture::TYPE_3D); Image::Image3DValidateError verr = Image::validate_3d_image(tex->format, tex->width, tex->height, tex->depth, tex->mipmaps > 1, p_data); @@ -926,10 +926,10 @@ void RendererStorageRD::texture_3d_update(RID p_texture, const Vector<Ref<Image> } void RendererStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(!tex->is_proxy); - Texture *proxy_to = texture_owner.getornull(p_proxy_to); + Texture *proxy_to = texture_owner.get_or_null(p_proxy_to); ERR_FAIL_COND(!proxy_to); ERR_FAIL_COND(proxy_to->is_proxy); @@ -943,7 +943,7 @@ void RendererStorageRD::texture_proxy_update(RID p_texture, RID p_proxy_to) { RD::get_singleton()->free(tex->rd_texture_srgb); tex->rd_texture_srgb = RID(); } - Texture *prev_tex = texture_owner.getornull(tex->proxy_to); + Texture *prev_tex = texture_owner.get_or_null(tex->proxy_to); ERR_FAIL_COND(!prev_tex); prev_tex->proxies.erase(p_texture); } @@ -1030,11 +1030,11 @@ void RendererStorageRD::texture_3d_placeholder_initialize(RID p_texture) { } Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND_V(!tex, Ref<Image>()); #ifdef TOOLS_ENABLED - if (tex->image_cache_2d.is_valid()) { + if (tex->image_cache_2d.is_valid() && !tex->is_render_target) { return tex->image_cache_2d; } #endif @@ -1049,7 +1049,7 @@ Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const { } #ifdef TOOLS_ENABLED - if (Engine::get_singleton()->is_editor_hint()) { + if (Engine::get_singleton()->is_editor_hint() && !tex->is_render_target) { tex->image_cache_2d = image; } #endif @@ -1058,7 +1058,7 @@ Ref<Image> RendererStorageRD::texture_2d_get(RID p_texture) const { } Ref<Image> RendererStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) const { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND_V(!tex, Ref<Image>()); Vector<uint8_t> data = RD::get_singleton()->texture_get_data(tex->rd_texture, p_layer); @@ -1075,7 +1075,7 @@ Ref<Image> RendererStorageRD::texture_2d_layer_get(RID p_texture, int p_layer) c } Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND_V(!tex, Vector<Ref<Image>>()); ERR_FAIL_COND_V(tex->type != Texture::TYPE_3D, Vector<Ref<Image>>()); @@ -1106,10 +1106,10 @@ Vector<Ref<Image>> RendererStorageRD::texture_3d_get(RID p_texture) const { } void RendererStorageRD::texture_replace(RID p_texture, RID p_by_texture) { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->proxy_to.is_valid()); //can't replace proxy - Texture *by_tex = texture_owner.getornull(p_by_texture); + Texture *by_tex = texture_owner.get_or_null(p_by_texture); ERR_FAIL_COND(!by_tex); ERR_FAIL_COND(by_tex->proxy_to.is_valid()); //can't replace proxy @@ -1155,7 +1155,7 @@ void RendererStorageRD::texture_replace(RID p_texture, RID p_by_texture) { } void RendererStorageRD::texture_set_size_override(RID p_texture, int p_width, int p_height) { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); ERR_FAIL_COND(tex->type != Texture::TYPE_2D); tex->width_2d = p_width; @@ -1163,7 +1163,7 @@ void RendererStorageRD::texture_set_size_override(RID p_texture, int p_width, in } void RendererStorageRD::texture_set_path(RID p_texture, const String &p_path) { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); tex->path = p_path; } @@ -1173,21 +1173,21 @@ String RendererStorageRD::texture_get_path(RID p_texture) const { } void RendererStorageRD::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); tex->detect_3d_callback_ud = p_userdata; tex->detect_3d_callback = p_callback; } void RendererStorageRD::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); tex->detect_normal_callback_ud = p_userdata; tex->detect_normal_callback = p_callback; } void RendererStorageRD::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) { - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); ERR_FAIL_COND(!tex); tex->detect_roughness_callback_ud = p_userdata; tex->detect_roughness_callback = p_callback; @@ -1227,6 +1227,100 @@ RendererStorageRD::CanvasTexture::~CanvasTexture() { clear_sets(); } +void RendererStorageRD::sampler_rd_configure_custom(float p_mipmap_bias) { + for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { + for (int j = 1; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { + RD::SamplerState sampler_state; + switch (i) { + case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.max_lod = 0; + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.max_lod = 0; + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST; + if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) { + sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST; + } else { + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } + sampler_state.lod_bias = p_mipmap_bias; + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) { + sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST; + } else { + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } + sampler_state.lod_bias = p_mipmap_bias; + + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST_WITH_MIPMAPS_ANISOTROPIC: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_NEAREST; + sampler_state.min_filter = RD::SAMPLER_FILTER_NEAREST; + if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) { + sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST; + } else { + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } + sampler_state.lod_bias = p_mipmap_bias; + sampler_state.use_anisotropy = true; + sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level")); + } break; + case RS::CANVAS_ITEM_TEXTURE_FILTER_LINEAR_WITH_MIPMAPS_ANISOTROPIC: { + sampler_state.mag_filter = RD::SAMPLER_FILTER_LINEAR; + sampler_state.min_filter = RD::SAMPLER_FILTER_LINEAR; + if (GLOBAL_GET("rendering/textures/default_filters/use_nearest_mipmap_filter")) { + sampler_state.mip_filter = RD::SAMPLER_FILTER_NEAREST; + } else { + sampler_state.mip_filter = RD::SAMPLER_FILTER_LINEAR; + } + sampler_state.lod_bias = p_mipmap_bias; + sampler_state.use_anisotropy = true; + sampler_state.anisotropy_max = 1 << int(GLOBAL_GET("rendering/textures/default_filters/anisotropic_filtering_level")); + + } break; + default: { + } + } + switch (j) { + case RS::CANVAS_ITEM_TEXTURE_REPEAT_DISABLED: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_CLAMP_TO_EDGE; + + } break; + case RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_REPEAT; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_REPEAT; + sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_REPEAT; + } break; + case RS::CANVAS_ITEM_TEXTURE_REPEAT_MIRROR: { + sampler_state.repeat_u = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler_state.repeat_v = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + sampler_state.repeat_w = RD::SAMPLER_REPEAT_MODE_MIRRORED_REPEAT; + } break; + default: { + } + } + + if (custom_rd_samplers[i][j].is_valid()) { + RD::get_singleton()->free(custom_rd_samplers[i][j]); + } + + custom_rd_samplers[i][j] = RD::get_singleton()->sampler_create(sampler_state); + } + } +} + RID RendererStorageRD::canvas_texture_allocate() { return canvas_texture_owner.allocate_rid(); } @@ -1235,7 +1329,7 @@ void RendererStorageRD::canvas_texture_initialize(RID p_rid) { } void RendererStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::CanvasTextureChannel p_channel, RID p_texture) { - CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); + CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); switch (p_channel) { case RS::CANVAS_TEXTURE_CHANNEL_DIFFUSE: { ct->diffuse = p_texture; @@ -1252,7 +1346,7 @@ void RendererStorageRD::canvas_texture_set_channel(RID p_canvas_texture, RS::Can } void RendererStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_texture, const Color &p_specular_color, float p_shininess) { - CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); + CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); ct->specular_color.r = p_specular_color.r; ct->specular_color.g = p_specular_color.g; ct->specular_color.b = p_specular_color.b; @@ -1261,13 +1355,13 @@ void RendererStorageRD::canvas_texture_set_shading_parameters(RID p_canvas_textu } void RendererStorageRD::canvas_texture_set_texture_filter(RID p_canvas_texture, RS::CanvasItemTextureFilter p_filter) { - CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); + CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); ct->texture_filter = p_filter; ct->clear_sets(); } void RendererStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, RS::CanvasItemTextureRepeat p_repeat) { - CanvasTexture *ct = canvas_texture_owner.getornull(p_canvas_texture); + CanvasTexture *ct = canvas_texture_owner.get_or_null(p_canvas_texture); ct->texture_repeat = p_repeat; ct->clear_sets(); } @@ -1275,7 +1369,7 @@ void RendererStorageRD::canvas_texture_set_texture_repeat(RID p_canvas_texture, bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID p_base_shader, int p_base_set, RID &r_uniform_set, Size2i &r_size, Color &r_specular_shininess, bool &r_use_normal, bool &r_use_specular) { CanvasTexture *ct = nullptr; - Texture *t = texture_owner.getornull(p_texture); + Texture *t = texture_owner.get_or_null(p_texture); if (t) { //regular texture @@ -1286,7 +1380,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas ct = t->canvas_texture; } else { - ct = canvas_texture_owner.getornull(p_texture); + ct = canvas_texture_owner.get_or_null(p_texture); } if (!ct) { @@ -1308,7 +1402,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 0; - t = texture_owner.getornull(ct->diffuse); + t = texture_owner.get_or_null(ct->diffuse); if (!t) { u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE)); ct->size_cache = Size2i(1, 1); @@ -1323,7 +1417,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 1; - t = texture_owner.getornull(ct->normal_map); + t = texture_owner.get_or_null(ct->normal_map); if (!t) { u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL)); ct->use_normal_cache = false; @@ -1338,7 +1432,7 @@ bool RendererStorageRD::canvas_texture_get_uniform_set(RID p_texture, RS::Canvas u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; u.binding = 2; - t = texture_owner.getornull(ct->specular); + t = texture_owner.get_or_null(ct->specular); if (!t) { u.ids.push_back(texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE)); ct->use_specular_cache = false; @@ -1384,7 +1478,7 @@ void RendererStorageRD::shader_initialize(RID p_rid) { } void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) { - Shader *shader = shader_owner.getornull(p_shader); + Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_COND(!shader); shader->code = p_code; @@ -1399,6 +1493,8 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) { new_type = SHADER_TYPE_3D; } else if (mode_string == "sky") { new_type = SHADER_TYPE_SKY; + } else if (mode_string == "fog") { + new_type = SHADER_TYPE_FOG; } else { new_type = SHADER_TYPE_MAX; } @@ -1438,8 +1534,10 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) { } if (shader->data) { - for (Map<StringName, RID>::Element *E = shader->default_texture_parameter.front(); E; E = E->next()) { - shader->data->set_default_texture_param(E->key(), E->get()); + for (const KeyValue<StringName, Map<int, RID>> &E : shader->default_texture_parameter) { + for (const KeyValue<int, RID> &E2 : E.value) { + shader->data->set_default_texture_param(E.key, E2.value, E2.key); + } } } } @@ -1456,30 +1554,39 @@ void RendererStorageRD::shader_set_code(RID p_shader, const String &p_code) { } String RendererStorageRD::shader_get_code(RID p_shader) const { - Shader *shader = shader_owner.getornull(p_shader); + Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_COND_V(!shader, String()); return shader->code; } void RendererStorageRD::shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const { - Shader *shader = shader_owner.getornull(p_shader); + Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_COND(!shader); if (shader->data) { return shader->data->get_param_list(p_param_list); } } -void RendererStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) { - Shader *shader = shader_owner.getornull(p_shader); +void RendererStorageRD::shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) { + Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_COND(!shader); if (p_texture.is_valid() && texture_owner.owns(p_texture)) { - shader->default_texture_parameter[p_name] = p_texture; + if (!shader->default_texture_parameter.has(p_name)) { + shader->default_texture_parameter[p_name] = Map<int, RID>(); + } + shader->default_texture_parameter[p_name][p_index] = p_texture; } else { - shader->default_texture_parameter.erase(p_name); + if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) { + shader->default_texture_parameter[p_name].erase(p_index); + + if (shader->default_texture_parameter[p_name].is_empty()) { + shader->default_texture_parameter.erase(p_name); + } + } } if (shader->data) { - shader->data->set_default_texture_param(p_name, p_texture); + shader->data->set_default_texture_param(p_name, p_texture, p_index); } for (Set<Material *>::Element *E = shader->owners.front(); E; E = E->next()) { Material *material = E->get(); @@ -1487,18 +1594,18 @@ void RendererStorageRD::shader_set_default_texture_param(RID p_shader, const Str } } -RID RendererStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name) const { - Shader *shader = shader_owner.getornull(p_shader); +RID RendererStorageRD::shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const { + Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_COND_V(!shader, RID()); - if (shader->default_texture_parameter.has(p_name)) { - return shader->default_texture_parameter[p_name]; + if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) { + return shader->default_texture_parameter[p_name][p_index]; } return RID(); } Variant RendererStorageRD::shader_get_param_default(RID p_shader, const StringName &p_param) const { - Shader *shader = shader_owner.getornull(p_shader); + Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_COND_V(!shader, Variant()); if (shader->data) { return shader->data->get_default_parameter(p_param); @@ -1512,7 +1619,7 @@ void RendererStorageRD::shader_set_data_request_function(ShaderType p_shader_typ } RS::ShaderNativeSourceCode RendererStorageRD::shader_get_native_source_code(RID p_shader) const { - Shader *shader = shader_owner.getornull(p_shader); + Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_COND_V(!shader, RS::ShaderNativeSourceCode()); if (shader->data) { return shader->data->get_native_source_code(); @@ -1527,7 +1634,7 @@ RID RendererStorageRD::material_allocate() { } void RendererStorageRD::material_initialize(RID p_rid) { material_owner.initialize_rid(p_rid); - Material *material = material_owner.getornull(p_rid); + Material *material = material_owner.get_or_null(p_rid); material->self = p_rid; } @@ -1543,7 +1650,7 @@ void RendererStorageRD::_material_queue_update(Material *material, bool p_unifor } void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND(!material); if (material->data) { @@ -1563,7 +1670,7 @@ void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) { return; } - Shader *shader = shader_owner.getornull(p_shader); + Shader *shader = shader_owner.get_or_null(p_shader); ERR_FAIL_COND(!shader); material->shader = shader; material->shader_type = shader->type; @@ -1586,7 +1693,7 @@ void RendererStorageRD::material_set_shader(RID p_material, RID p_shader) { } void RendererStorageRD::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND(!material); if (p_value.get_type() == Variant::NIL) { @@ -1605,7 +1712,7 @@ void RendererStorageRD::material_set_param(RID p_material, const StringName &p_p } Variant RendererStorageRD::material_get_param(RID p_material, const StringName &p_param) const { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND_V(!material, Variant()); if (material->params.has(p_param)) { return material->params[p_param]; @@ -1615,7 +1722,7 @@ Variant RendererStorageRD::material_get_param(RID p_material, const StringName & } void RendererStorageRD::material_set_next_pass(RID p_material, RID p_next_material) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND(!material); if (material->next_pass == p_next_material) { @@ -1631,7 +1738,7 @@ void RendererStorageRD::material_set_next_pass(RID p_material, RID p_next_materi } void RendererStorageRD::material_set_render_priority(RID p_material, int priority) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND(!material); material->priority = priority; if (material->data) { @@ -1640,7 +1747,7 @@ void RendererStorageRD::material_set_render_priority(RID p_material, int priorit } bool RendererStorageRD::material_is_animated(RID p_material) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND_V(!material, false); if (material->shader && material->shader->data) { if (material->shader->data->is_animated()) { @@ -1653,7 +1760,7 @@ bool RendererStorageRD::material_is_animated(RID p_material) { } bool RendererStorageRD::material_casts_shadows(RID p_material) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND_V(!material, true); if (material->shader && material->shader->data) { if (material->shader->data->casts_shadows()) { @@ -1666,7 +1773,7 @@ bool RendererStorageRD::material_casts_shadows(RID p_material) { } void RendererStorageRD::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND(!material); if (material->shader && material->shader->data) { material->shader->data->get_instance_param_list(r_parameters); @@ -1678,7 +1785,7 @@ void RendererStorageRD::material_get_instance_shader_parameters(RID p_material, } void RendererStorageRD::material_update_dependency(RID p_material, DependencyTracker *p_instance) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); ERR_FAIL_COND(!material); p_instance->update_dependency(&material->dependency); if (material->next_pass.is_valid()) { @@ -1691,73 +1798,183 @@ void RendererStorageRD::material_set_data_request_function(ShaderType p_shader_t material_data_request_func[p_shader_type] = p_function; } -_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) { +_FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, int p_array_size, const Variant &value, uint8_t *data, bool p_linear_color) { switch (type) { case ShaderLanguage::TYPE_BOOL: { - bool v = value; - uint32_t *gui = (uint32_t *)data; - *gui = v ? 1 : 0; + + if (p_array_size > 0) { + const PackedInt32Array &ba = value; + int s = ba.size(); + const int *r = ba.ptr(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = (r[i] != 0) ? 1 : 0; + } else { + gui[j] = 0; + } + gui[j + 1] = 0; // ignored + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + bool v = value; + gui[0] = v ? 1 : 0; + } } break; case ShaderLanguage::TYPE_BVEC2: { - int v = value; uint32_t *gui = (uint32_t *)data; - gui[0] = v & 1 ? 1 : 0; - gui[1] = v & 2 ? 1 : 0; + if (p_array_size > 0) { + const PackedInt32Array &ba = value; + int s = ba.size(); + const int *r = ba.ptr(); + int count = 2 * p_array_size; + + for (int i = 0, j = 0; i < count; i += 2, j += 4) { + if (i < s) { + gui[j] = r[i] ? 1 : 0; + gui[j + 1] = r[i + 1] ? 1 : 0; + } else { + gui[j] = 0; + gui[j + 1] = 0; + } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + int v = value; + gui[0] = v & 1 ? 1 : 0; + gui[1] = v & 2 ? 1 : 0; + } } break; case ShaderLanguage::TYPE_BVEC3: { - int v = value; uint32_t *gui = (uint32_t *)data; - gui[0] = (v & 1) ? 1 : 0; - gui[1] = (v & 2) ? 1 : 0; - gui[2] = (v & 4) ? 1 : 0; + if (p_array_size > 0) { + const PackedInt32Array &ba = value; + int s = ba.size(); + const int *r = ba.ptr(); + int count = 3 * p_array_size; + + for (int i = 0, j = 0; i < count; i += 3, j += 4) { + if (i < s) { + gui[j] = r[i] ? 1 : 0; + gui[j + 1] = r[i + 1] ? 1 : 0; + gui[j + 2] = r[i + 2] ? 1 : 0; + } else { + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; + } + gui[j + 3] = 0; // ignored + } + } else { + int v = value; + gui[0] = (v & 1) ? 1 : 0; + gui[1] = (v & 2) ? 1 : 0; + gui[2] = (v & 4) ? 1 : 0; + } } break; case ShaderLanguage::TYPE_BVEC4: { - int v = value; uint32_t *gui = (uint32_t *)data; - gui[0] = (v & 1) ? 1 : 0; - gui[1] = (v & 2) ? 1 : 0; - gui[2] = (v & 4) ? 1 : 0; - gui[3] = (v & 8) ? 1 : 0; + if (p_array_size > 0) { + const PackedInt32Array &ba = value; + int s = ba.size(); + const int *r = ba.ptr(); + int count = 4 * p_array_size; + + for (int i = 0; i < count; i += 4) { + if (i < s) { + gui[i] = r[i] ? 1 : 0; + gui[i + 1] = r[i + 1] ? 1 : 0; + gui[i + 2] = r[i + 2] ? 1 : 0; + gui[i + 3] = r[i + 3] ? 1 : 0; + } else { + gui[i] = 0; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; + } + } + } else { + int v = value; + gui[0] = (v & 1) ? 1 : 0; + gui[1] = (v & 2) ? 1 : 0; + gui[2] = (v & 4) ? 1 : 0; + gui[3] = (v & 8) ? 1 : 0; + } } break; case ShaderLanguage::TYPE_INT: { - int v = value; int32_t *gui = (int32_t *)data; - gui[0] = v; + if (p_array_size > 0) { + Vector<int> iv = value; + int s = iv.size(); + const int *r = iv.ptr(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = r[i]; + } else { + gui[j] = 0; + } + gui[j + 1] = 0; // ignored + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + int v = value; + gui[0] = v; + } } break; case ShaderLanguage::TYPE_IVEC2: { Vector<int> iv = value; int s = iv.size(); int32_t *gui = (int32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 2 * p_array_size; - for (int i = 0; i < 2; i++) { + const int *r = iv.ptr(); + for (int i = 0, j = 0; i < count; i += 2, j += 4) { if (i < s) { - gui[i] = r[i]; + gui[j] = r[i]; + gui[j + 1] = r[i + 1]; } else { - gui[i] = 0; + gui[j] = 0; + gui[j + 1] = 0; } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored } - } break; case ShaderLanguage::TYPE_IVEC3: { Vector<int> iv = value; int s = iv.size(); int32_t *gui = (int32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 3 * p_array_size; - for (int i = 0; i < 3; i++) { + const int *r = iv.ptr(); + for (int i = 0, j = 0; i < count; i += 3, j += 4) { if (i < s) { - gui[i] = r[i]; + gui[j] = r[i]; + gui[j + 1] = r[i + 1]; + gui[j + 2] = r[i + 2]; } else { - gui[i] = 0; + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; } + gui[j + 3] = 0; // ignored } } break; case ShaderLanguage::TYPE_IVEC4: { @@ -1765,35 +1982,70 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int s = iv.size(); int32_t *gui = (int32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 4 * p_array_size; - for (int i = 0; i < 4; i++) { + const int *r = iv.ptr(); + for (int i = 0; i < count; i += 4) { if (i < s) { gui[i] = r[i]; + gui[i + 1] = r[i + 1]; + gui[i + 2] = r[i + 2]; + gui[i + 3] = r[i + 3]; } else { gui[i] = 0; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; } } } break; case ShaderLanguage::TYPE_UINT: { - int v = value; uint32_t *gui = (uint32_t *)data; - gui[0] = v; + if (p_array_size > 0) { + Vector<int> iv = value; + int s = iv.size(); + const int *r = iv.ptr(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = r[i]; + } else { + gui[j] = 0; + } + gui[j + 1] = 0; // ignored + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + int v = value; + gui[0] = v; + } } break; case ShaderLanguage::TYPE_UVEC2: { Vector<int> iv = value; int s = iv.size(); uint32_t *gui = (uint32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 2 * p_array_size; - for (int i = 0; i < 2; i++) { + const int *r = iv.ptr(); + for (int i = 0, j = 0; i < count; i += 2, j += 4) { if (i < s) { - gui[i] = r[i]; + gui[j] = r[i]; + gui[j + 1] = r[i + 1]; } else { - gui[i] = 0; + gui[j] = 0; + gui[j + 1] = 0; } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored } } break; case ShaderLanguage::TYPE_UVEC3: { @@ -1801,141 +2053,370 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int s = iv.size(); uint32_t *gui = (uint32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 3 * p_array_size; - for (int i = 0; i < 3; i++) { + const int *r = iv.ptr(); + for (int i = 0, j = 0; i < count; i += 3, j += 4) { if (i < s) { - gui[i] = r[i]; + gui[j] = r[i]; + gui[j + 1] = r[i + 1]; + gui[j + 2] = r[i + 2]; } else { - gui[i] = 0; + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; } + gui[j + 3] = 0; // ignored } - } break; case ShaderLanguage::TYPE_UVEC4: { Vector<int> iv = value; int s = iv.size(); uint32_t *gui = (uint32_t *)data; - const int *r = iv.ptr(); + if (p_array_size <= 0) { + p_array_size = 1; + } + int count = 4 * p_array_size; - for (int i = 0; i < 4; i++) { + const int *r = iv.ptr(); + for (int i = 0; i < count; i++) { if (i < s) { gui[i] = r[i]; + gui[i + 1] = r[i + 1]; + gui[i + 2] = r[i + 2]; + gui[i + 3] = r[i + 3]; } else { gui[i] = 0; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; } } } break; case ShaderLanguage::TYPE_FLOAT: { - float v = value; float *gui = (float *)data; - gui[0] = v; + if (p_array_size > 0) { + const PackedFloat32Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = a[i]; + } else { + gui[j] = 0; + } + gui[j + 1] = 0; // ignored + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + float v = value; + gui[0] = v; + } } break; case ShaderLanguage::TYPE_VEC2: { - Vector2 v = value; float *gui = (float *)data; - gui[0] = v.x; - gui[1] = v.y; + if (p_array_size > 0) { + const PackedVector2Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = a[i].x; + gui[j + 1] = a[i].y; + } else { + gui[j] = 0; + gui[j + 1] = 0; + } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + } + } else { + Vector2 v = value; + gui[0] = v.x; + gui[1] = v.y; + } } break; case ShaderLanguage::TYPE_VEC3: { - Vector3 v = value; float *gui = (float *)data; - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; + if (p_array_size > 0) { + const PackedVector3Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + gui[j] = a[i].x; + gui[j + 1] = a[i].y; + gui[j + 2] = a[i].z; + } else { + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; + } + gui[j + 3] = 0; // ignored + } + } else { + Vector3 v = value; + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; + } } break; case ShaderLanguage::TYPE_VEC4: { float *gui = (float *)data; - if (value.get_type() == Variant::COLOR) { - Color v = value; + if (p_array_size > 0) { + if (value.get_type() == Variant::PACKED_COLOR_ARRAY) { + const PackedColorArray &a = value; + int s = a.size(); - if (p_linear_color) { - v = v.to_linear(); + for (int i = 0, j = 0; i < p_array_size; i++, j += 4) { + if (i < s) { + Color color = a[i]; + if (p_linear_color) { + color = color.to_linear(); + } + gui[j] = color.r; + gui[j + 1] = color.g; + gui[j + 2] = color.b; + gui[j + 3] = color.a; + } else { + gui[j] = 0; + gui[j + 1] = 0; + gui[j + 2] = 0; + gui[j + 3] = 0; + } + } + } else { + const PackedFloat32Array &a = value; + int s = a.size(); + int count = 4 * p_array_size; + + for (int i = 0; i < count; i += 4) { + if (i + 3 < s) { + gui[i] = a[i]; + gui[i + 1] = a[i + 1]; + gui[i + 2] = a[i + 2]; + gui[i + 3] = a[i + 3]; + } else { + gui[i] = 0; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; + } + } } + } else { + if (value.get_type() == Variant::COLOR) { + Color v = value; - gui[0] = v.r; - gui[1] = v.g; - gui[2] = v.b; - gui[3] = v.a; - } else if (value.get_type() == Variant::RECT2) { - Rect2 v = value; - - gui[0] = v.position.x; - gui[1] = v.position.y; - gui[2] = v.size.x; - gui[3] = v.size.y; - } else if (value.get_type() == Variant::QUATERNION) { - Quaternion v = value; + if (p_linear_color) { + v = v.to_linear(); + } - gui[0] = v.x; - gui[1] = v.y; - gui[2] = v.z; - gui[3] = v.w; - } else { - Plane v = value; + gui[0] = v.r; + gui[1] = v.g; + gui[2] = v.b; + gui[3] = v.a; + } else if (value.get_type() == Variant::RECT2) { + Rect2 v = value; + + gui[0] = v.position.x; + gui[1] = v.position.y; + gui[2] = v.size.x; + gui[3] = v.size.y; + } else if (value.get_type() == Variant::QUATERNION) { + Quaternion v = value; + + gui[0] = v.x; + gui[1] = v.y; + gui[2] = v.z; + gui[3] = v.w; + } else { + Plane v = value; - gui[0] = v.normal.x; - gui[1] = v.normal.y; - gui[2] = v.normal.z; - gui[3] = v.d; + gui[0] = v.normal.x; + gui[1] = v.normal.y; + gui[2] = v.normal.z; + gui[3] = v.d; + } } } break; case ShaderLanguage::TYPE_MAT2: { - Transform2D v = value; float *gui = (float *)data; - //in std140 members of mat2 are treated as vec4s - gui[0] = v.elements[0][0]; - gui[1] = v.elements[0][1]; - gui[2] = 0; - gui[3] = 0; - gui[4] = v.elements[1][0]; - gui[5] = v.elements[1][1]; - gui[6] = 0; - gui[7] = 0; + if (p_array_size > 0) { + const PackedFloat32Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size * 4; i += 4, j += 8) { + if (i + 3 < s) { + gui[j] = a[i]; + gui[j + 1] = a[i + 1]; + + gui[j + 4] = a[i + 2]; + gui[j + 5] = a[i + 3]; + } else { + gui[j] = 1; + gui[j + 1] = 0; + + gui[j + 4] = 0; + gui[j + 5] = 1; + } + gui[j + 2] = 0; // ignored + gui[j + 3] = 0; // ignored + gui[j + 6] = 0; // ignored + gui[j + 7] = 0; // ignored + } + } else { + Transform2D v = value; + + //in std140 members of mat2 are treated as vec4s + gui[0] = v.elements[0][0]; + gui[1] = v.elements[0][1]; + gui[2] = 0; // ignored + gui[3] = 0; // ignored + + gui[4] = v.elements[1][0]; + gui[5] = v.elements[1][1]; + gui[6] = 0; // ignored + gui[7] = 0; // ignored + } } break; case ShaderLanguage::TYPE_MAT3: { - Basis v = value; float *gui = (float *)data; - gui[0] = v.elements[0][0]; - gui[1] = v.elements[1][0]; - gui[2] = v.elements[2][0]; - gui[3] = 0; - gui[4] = v.elements[0][1]; - gui[5] = v.elements[1][1]; - gui[6] = v.elements[2][1]; - gui[7] = 0; - gui[8] = v.elements[0][2]; - gui[9] = v.elements[1][2]; - gui[10] = v.elements[2][2]; - gui[11] = 0; + if (p_array_size > 0) { + const PackedFloat32Array &a = value; + int s = a.size(); + + for (int i = 0, j = 0; i < p_array_size * 9; i += 9, j += 12) { + if (i + 8 < s) { + gui[j] = a[i]; + gui[j + 1] = a[i + 1]; + gui[j + 2] = a[i + 2]; + + gui[j + 4] = a[i + 3]; + gui[j + 5] = a[i + 4]; + gui[j + 6] = a[i + 5]; + + gui[j + 8] = a[i + 6]; + gui[j + 9] = a[i + 7]; + gui[j + 10] = a[i + 8]; + } else { + gui[j] = 1; + gui[j + 1] = 0; + gui[j + 2] = 0; + + gui[j + 4] = 0; + gui[j + 5] = 1; + gui[j + 6] = 0; + + gui[j + 8] = 0; + gui[j + 9] = 0; + gui[j + 10] = 1; + } + gui[j + 3] = 0; // ignored + gui[j + 7] = 0; // ignored + gui[j + 11] = 0; // ignored + } + } else { + Basis v = value; + gui[0] = v.elements[0][0]; + gui[1] = v.elements[1][0]; + gui[2] = v.elements[2][0]; + gui[3] = 0; // ignored + + gui[4] = v.elements[0][1]; + gui[5] = v.elements[1][1]; + gui[6] = v.elements[2][1]; + gui[7] = 0; // ignored + + gui[8] = v.elements[0][2]; + gui[9] = v.elements[1][2]; + gui[10] = v.elements[2][2]; + gui[11] = 0; // ignored + } } break; case ShaderLanguage::TYPE_MAT4: { - Transform3D v = value; float *gui = (float *)data; - gui[0] = v.basis.elements[0][0]; - gui[1] = v.basis.elements[1][0]; - gui[2] = v.basis.elements[2][0]; - gui[3] = 0; - gui[4] = v.basis.elements[0][1]; - gui[5] = v.basis.elements[1][1]; - gui[6] = v.basis.elements[2][1]; - gui[7] = 0; - gui[8] = v.basis.elements[0][2]; - gui[9] = v.basis.elements[1][2]; - gui[10] = v.basis.elements[2][2]; - gui[11] = 0; - gui[12] = v.origin.x; - gui[13] = v.origin.y; - gui[14] = v.origin.z; - gui[15] = 1; + if (p_array_size > 0) { + const PackedFloat32Array &a = value; + int s = a.size(); + + for (int i = 0; i < p_array_size * 16; i += 16) { + if (i + 15 < s) { + gui[i] = a[i]; + gui[i + 1] = a[i + 1]; + gui[i + 2] = a[i + 2]; + gui[i + 3] = a[i + 3]; + + gui[i + 4] = a[i + 4]; + gui[i + 5] = a[i + 5]; + gui[i + 6] = a[i + 6]; + gui[i + 7] = a[i + 7]; + + gui[i + 8] = a[i + 8]; + gui[i + 9] = a[i + 9]; + gui[i + 10] = a[i + 10]; + gui[i + 11] = a[i + 11]; + + gui[i + 12] = a[i + 12]; + gui[i + 13] = a[i + 13]; + gui[i + 14] = a[i + 14]; + gui[i + 15] = a[i + 15]; + } else { + gui[i] = 1; + gui[i + 1] = 0; + gui[i + 2] = 0; + gui[i + 3] = 0; + + gui[i + 4] = 0; + gui[i + 5] = 1; + gui[i + 6] = 0; + gui[i + 7] = 0; + + gui[i + 8] = 0; + gui[i + 9] = 0; + gui[i + 10] = 1; + gui[i + 11] = 0; + + gui[i + 12] = 0; + gui[i + 13] = 0; + gui[i + 14] = 0; + gui[i + 15] = 1; + } + } + } else { + Transform3D v = value; + gui[0] = v.basis.elements[0][0]; + gui[1] = v.basis.elements[1][0]; + gui[2] = v.basis.elements[2][0]; + gui[3] = 0; + + gui[4] = v.basis.elements[0][1]; + gui[5] = v.basis.elements[1][1]; + gui[6] = v.basis.elements[2][1]; + gui[7] = 0; + + gui[8] = v.basis.elements[0][2]; + gui[9] = v.basis.elements[1][2]; + gui[10] = v.basis.elements[2][2]; + gui[11] = 0; + + gui[12] = v.origin.x; + gui[13] = v.origin.y; + gui[14] = v.origin.z; + gui[15] = 1; + } } break; default: { } @@ -2094,19 +2575,23 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, } } -_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, uint8_t *data) { +_FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, int p_array_size, uint8_t *data) { + if (p_array_size <= 0) { + p_array_size = 1; + } + switch (type) { case ShaderLanguage::TYPE_BOOL: case ShaderLanguage::TYPE_INT: case ShaderLanguage::TYPE_UINT: case ShaderLanguage::TYPE_FLOAT: { - memset(data, 0, 4); + memset(data, 0, 4 * p_array_size); } break; case ShaderLanguage::TYPE_BVEC2: case ShaderLanguage::TYPE_IVEC2: case ShaderLanguage::TYPE_UVEC2: case ShaderLanguage::TYPE_VEC2: { - memset(data, 0, 8); + memset(data, 0, 8 * p_array_size); } break; case ShaderLanguage::TYPE_BVEC3: case ShaderLanguage::TYPE_IVEC3: @@ -2116,16 +2601,16 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, case ShaderLanguage::TYPE_IVEC4: case ShaderLanguage::TYPE_UVEC4: case ShaderLanguage::TYPE_VEC4: { - memset(data, 0, 16); + memset(data, 0, 16 * p_array_size); } break; case ShaderLanguage::TYPE_MAT2: { - memset(data, 0, 32); + memset(data, 0, 32 * p_array_size); } break; case ShaderLanguage::TYPE_MAT3: { - memset(data, 0, 48); + memset(data, 0, 48 * p_array_size); } break; case ShaderLanguage::TYPE_MAT4: { - memset(data, 0, 64); + memset(data, 0, 64 * p_array_size); } break; default: { @@ -2136,28 +2621,28 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color) { bool uses_global_buffer = false; - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_uniforms.front(); E; E = E->next()) { - if (E->get().order < 0) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : p_uniforms) { + if (E.value.order < 0) { continue; // texture, does not go here } - if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; //instance uniforms don't appear in the bufferr } - if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { + if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { //this is a global variable, get the index to it RendererStorageRD *rs = base_singleton; - GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E->key()); + GlobalVariables::Variable *gv = rs->global_variables.variables.getptr(E.key); uint32_t index = 0; if (gv) { index = gv->buffer_index; } else { - WARN_PRINT("Shader uses global uniform '" + E->key() + "', but it was removed at some point. Material will not display correctly."); + WARN_PRINT("Shader uses global uniform '" + E.key + "', but it was removed at some point. Material will not display correctly."); } - uint32_t offset = p_uniform_offsets[E->get().order]; + uint32_t offset = p_uniform_offsets[E.value.order]; uint32_t *intptr = (uint32_t *)&p_buffer[offset]; *intptr = index; uses_global_buffer = true; @@ -2165,30 +2650,30 @@ void RendererStorageRD::MaterialData::update_uniform_buffer(const Map<StringName } //regular uniform - uint32_t offset = p_uniform_offsets[E->get().order]; + uint32_t offset = p_uniform_offsets[E.value.order]; #ifdef DEBUG_ENABLED - uint32_t size = ShaderLanguage::get_type_size(E->get().type); + uint32_t size = ShaderLanguage::get_type_size(E.value.type); ERR_CONTINUE(offset + size > p_buffer_size); #endif uint8_t *data = &p_buffer[offset]; - const Map<StringName, Variant>::Element *V = p_parameters.find(E->key()); + const Map<StringName, Variant>::Element *V = p_parameters.find(E.key); if (V) { //user provided - _fill_std140_variant_ubo_value(E->get().type, V->get(), data, p_use_linear_color); + _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, V->get(), data, p_use_linear_color); - } else if (E->get().default_value.size()) { + } else if (E.value.default_value.size()) { //default value - _fill_std140_ubo_value(E->get().type, E->get().default_value, data); - //value=E->get().default_value; + _fill_std140_ubo_value(E.value.type, E.value.default_value, data); + //value=E.value.default_value; } else { //zero because it was not provided - if (E->get().type == ShaderLanguage::TYPE_VEC4 && E->get().hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + if (E.value.type == ShaderLanguage::TYPE_VEC4 && E.value.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { //colors must be set as black, with alpha as 1.0 - _fill_std140_variant_ubo_value(E->get().type, Color(0, 0, 0, 1), data, p_use_linear_color); + _fill_std140_variant_ubo_value(E.value.type, E.value.array_size, Color(0, 0, 0, 1), data, p_use_linear_color); } else { //else just zero it out - _fill_std140_ubo_empty(E->get().type, data); + _fill_std140_ubo_empty(E.value.type, E.value.array_size, data); } } } @@ -2215,8 +2700,8 @@ RendererStorageRD::MaterialData::~MaterialData() { //unregister global textures RendererStorageRD *rs = base_singleton; - for (Map<StringName, uint64_t>::Element *E = used_global_textures.front(); E; E = E->next()) { - GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E->key()); + for (const KeyValue<StringName, uint64_t> &E : used_global_textures) { + GlobalVariables::Variable *v = rs->global_variables.variables.getptr(E.key); if (v) { v->texture_materials.erase(self); } @@ -2230,7 +2715,7 @@ RendererStorageRD::MaterialData::~MaterialData() { } } -void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { +void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, Map<int, RID>> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color) { RendererStorageRD *singleton = (RendererStorageRD *)RendererStorage::base_singleton; #ifdef TOOLS_ENABLED Texture *roughness_detect_texture = nullptr; @@ -2241,10 +2726,11 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari bool uses_global_textures = false; global_textures_pass++; - for (int i = 0; i < p_texture_uniforms.size(); i++) { + for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) { const StringName &uniform_name = p_texture_uniforms[i].name; + int uniform_array_size = p_texture_uniforms[i].array_size; - RID texture; + Vector<RID> textures; if (p_texture_uniforms[i].global) { RendererStorageRD *rs = base_singleton; @@ -2265,86 +2751,154 @@ void RendererStorageRD::MaterialData::update_textures(const Map<StringName, Vari E->get() = global_textures_pass; } - texture = v->override.get_type() != Variant::NIL ? v->override : v->value; + textures.push_back(v->override.get_type() != Variant::NIL ? v->override : v->value); } } else { WARN_PRINT("Shader uses global uniform texture '" + String(uniform_name) + "', but it was removed at some point. Material will not display correctly."); } } else { - if (!texture.is_valid()) { - const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name); - if (V) { - texture = V->get(); + const Map<StringName, Variant>::Element *V = p_parameters.find(uniform_name); + if (V) { + if (V->get().is_array()) { + Array array = (Array)V->get(); + if (uniform_array_size > 0) { + for (int j = 0; j < array.size(); j++) { + textures.push_back(array[j]); + } + } else { + if (array.size() > 0) { + textures.push_back(array[0]); + } + } + } else { + textures.push_back(V->get()); } } - if (!texture.is_valid()) { - const Map<StringName, RID>::Element *W = p_default_textures.find(uniform_name); - if (W) { - texture = W->get(); + if (uniform_array_size > 0) { + if (textures.size() < uniform_array_size) { + const Map<StringName, Map<int, RID>>::Element *W = p_default_textures.find(uniform_name); + for (int j = textures.size(); j < uniform_array_size; j++) { + if (W && W->get().has(j)) { + textures.push_back(W->get()[j]); + } else { + textures.push_back(RID()); + } + } + } + } else if (textures.is_empty()) { + const Map<StringName, Map<int, RID>>::Element *W = p_default_textures.find(uniform_name); + if (W && W->get().has(0)) { + textures.push_back(W->get()[0]); } } } RID rd_texture; - if (texture.is_null()) { + if (textures.is_empty()) { //check default usage - switch (p_texture_uniforms[i].hint) { - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: - case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: { - rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK); + switch (p_texture_uniforms[i].type) { + case ShaderLanguage::TYPE_ISAMPLER2D: + case ShaderLanguage::TYPE_USAMPLER2D: + case ShaderLanguage::TYPE_SAMPLER2D: { + switch (p_texture_uniforms[i].hint) { + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_BLACK); + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL); + } break; + case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO); + } break; + default: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); + } break; + } } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_NONE: { - rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_NORMAL); + + case ShaderLanguage::TYPE_SAMPLERCUBE: { + switch (p_texture_uniforms[i].hint) { + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: + case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_BLACK); + } break; + default: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_WHITE); + } break; + } } break; - case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: { - rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_ANISO); + case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK); } break; - default: { - rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); + + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: + case ShaderLanguage::TYPE_SAMPLER3D: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_3D_WHITE); + } break; + + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER2DARRAY: { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE); } break; + + default: { + } + } +#ifdef TOOLS_ENABLED + if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); + } +#endif + if (uniform_array_size > 0) { + for (int j = 0; j < uniform_array_size; j++) { + p_textures[k++] = rd_texture; + } + } else { + p_textures[k++] = rd_texture; } } else { bool srgb = p_use_linear_color && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ALBEDO || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO); - Texture *tex = singleton->texture_owner.getornull(texture); + for (int j = 0; j < textures.size(); j++) { + Texture *tex = singleton->texture_owner.get_or_null(textures[j]); - if (tex) { - rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture; + if (tex) { + rd_texture = (srgb && tex->rd_texture_srgb.is_valid()) ? tex->rd_texture_srgb : tex->rd_texture; #ifdef TOOLS_ENABLED - if (tex->detect_3d_callback && p_use_linear_color) { - tex->detect_3d_callback(tex->detect_3d_callback_ud); - } - if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) { - if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) { - normal_detect_texture = tex; + if (tex->detect_3d_callback && p_use_linear_color) { + tex->detect_3d_callback(tex->detect_3d_callback_ud); + } + if (tex->detect_normal_callback && (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL || p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL)) { + if (p_texture_uniforms[i].hint == ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_NORMAL) { + normal_detect_texture = tex; + } + tex->detect_normal_callback(tex->detect_normal_callback_ud); + } + if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) { + //find the normal texture + roughness_detect_texture = tex; + roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R); } - tex->detect_normal_callback(tex->detect_normal_callback_ud); +#endif } - if (tex->detect_roughness_callback && (p_texture_uniforms[i].hint >= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R || p_texture_uniforms[i].hint <= ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_GRAY)) { - //find the normal texture - roughness_detect_texture = tex; - roughness_channel = RS::TextureDetectRoughnessChannel(p_texture_uniforms[i].hint - ShaderLanguage::ShaderNode::Uniform::HINT_ROUGHNESS_R); + if (rd_texture.is_null()) { + rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); + } +#ifdef TOOLS_ENABLED + if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { + roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); } - #endif - } - - if (rd_texture.is_null()) { - //wtf - rd_texture = singleton->texture_rd_get_default(DEFAULT_RD_TEXTURE_WHITE); + p_textures[k++] = rd_texture; } } - - p_textures[i] = rd_texture; } -#ifdef TOOLS_ENABLED - if (roughness_detect_texture && normal_detect_texture && normal_detect_texture->path != String()) { - roughness_detect_texture->detect_roughness_callback(roughness_detect_texture->detect_roughness_callback_ud, normal_detect_texture->path, roughness_channel); - } -#endif { //for textures no longer used, unregister them List<Map<StringName, uint64_t>::Element *> to_delete; @@ -2384,7 +2938,7 @@ void RendererStorageRD::MaterialData::free_parameters_uniform_set(RID p_uniform_ } } -bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, RID> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier) { +bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, Map<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier) { if ((uint32_t)ubo_data.size() != p_ubo_size) { p_uniform_dirty = true; if (uniform_buffer.is_valid()) { @@ -2408,11 +2962,14 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St //check whether buffer changed if (p_uniform_dirty && ubo_data.size()) { - update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), false); + update_uniform_buffer(p_uniforms, p_uniform_offsets, p_parameters, ubo_data.ptrw(), ubo_data.size(), true); RD::get_singleton()->buffer_update(uniform_buffer, 0, ubo_data.size(), ubo_data.ptrw(), p_barrier); } - uint32_t tex_uniform_count = p_texture_uniforms.size(); + uint32_t tex_uniform_count = 0U; + for (int i = 0; i < p_texture_uniforms.size(); i++) { + tex_uniform_count += uint32_t(p_texture_uniforms[i].array_size > 0 ? p_texture_uniforms[i].array_size : 1); + } if ((uint32_t)texture_cache.size() != tex_uniform_count || p_textures_dirty) { texture_cache.resize(tex_uniform_count); @@ -2452,11 +3009,19 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St } const RID *textures = texture_cache.ptrw(); - for (uint32_t i = 0; i < tex_uniform_count; i++) { + for (int i = 0, k = 0; i < p_texture_uniforms.size(); i++) { + const int array_size = p_texture_uniforms[i].array_size; + RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_TEXTURE; - u.binding = 1 + i; - u.ids.push_back(textures[i]); + u.binding = 1 + k; + if (array_size > 0) { + for (int j = 0; j < array_size; j++) { + u.ids.push_back(textures[k++]); + } + } else { + u.ids.push_back(textures[k++]); + } uniforms.push_back(u); } } @@ -2470,14 +3035,14 @@ bool RendererStorageRD::MaterialData::update_parameters_uniform_set(const Map<St void RendererStorageRD::_material_uniform_set_erased(const RID &p_set, void *p_material) { RID rid = *(RID *)p_material; - Material *material = base_singleton->material_owner.getornull(rid); + Material *material = base_singleton->material_owner.get_or_null(rid); if (material) { material->dependency.changed_notify(DEPENDENCY_CHANGED_MATERIAL); } } void RendererStorageRD::material_force_update_textures(RID p_material, ShaderType p_shader_type) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); if (material->shader_type != p_shader_type) { return; } @@ -2518,7 +3083,7 @@ void RendererStorageRD::mesh_initialize(RID p_rid) { void RendererStorageRD::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count) { ERR_FAIL_COND(p_blend_shape_count < 0); - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist @@ -2528,7 +3093,7 @@ void RendererStorageRD::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape /// Returns stride void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_COND(mesh->surface_count == RS::MAX_MESH_SURFACES); @@ -2732,13 +3297,13 @@ void RendererStorageRD::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_su } int RendererStorageRD::mesh_get_blend_shape_count(RID p_mesh) const { - const Mesh *mesh = mesh_owner.getornull(p_mesh); + const Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, -1); return mesh->blend_shape_count; } void RendererStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_INDEX((int)p_mode, 2); @@ -2746,13 +3311,13 @@ void RendererStorageRD::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode } RS::BlendShapeMode RendererStorageRD::mesh_get_blend_shape_mode(RID p_mesh) const { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED); return mesh->blend_shape_mode; } void RendererStorageRD::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); ERR_FAIL_COND(p_data.size() == 0); @@ -2763,7 +3328,7 @@ void RendererStorageRD::mesh_surface_update_vertex_region(RID p_mesh, int p_surf } void RendererStorageRD::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); ERR_FAIL_COND(p_data.size() == 0); @@ -2775,7 +3340,7 @@ void RendererStorageRD::mesh_surface_update_attribute_region(RID p_mesh, int p_s } void RendererStorageRD::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); ERR_FAIL_COND(p_data.size() == 0); @@ -2787,7 +3352,7 @@ void RendererStorageRD::mesh_surface_update_skin_region(RID p_mesh, int p_surfac } void RendererStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count); mesh->surfaces[p_surface]->material = p_material; @@ -2797,7 +3362,7 @@ void RendererStorageRD::mesh_surface_set_material(RID p_mesh, int p_surface, RID } RID RendererStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) const { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, RID()); ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID()); @@ -2805,7 +3370,7 @@ RID RendererStorageRD::mesh_surface_get_material(RID p_mesh, int p_surface) cons } RS::SurfaceData RendererStorageRD::mesh_get_surface(RID p_mesh, int p_surface) const { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, RS::SurfaceData()); ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData()); @@ -2845,32 +3410,32 @@ RS::SurfaceData RendererStorageRD::mesh_get_surface(RID p_mesh, int p_surface) c } int RendererStorageRD::mesh_get_surface_count(RID p_mesh) const { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, 0); return mesh->surface_count; } void RendererStorageRD::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); mesh->custom_aabb = p_aabb; } AABB RendererStorageRD::mesh_get_custom_aabb(RID p_mesh) const { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); return mesh->custom_aabb; } AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); if (mesh->custom_aabb != AABB()) { return mesh->custom_aabb; } - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); if (!skeleton || skeleton->size == 0) { return mesh->aabb; @@ -2968,16 +3533,16 @@ AABB RendererStorageRD::mesh_get_aabb(RID p_mesh, RID p_skeleton) { } void RendererStorageRD::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); - Mesh *shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh); + Mesh *shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh); if (shadow_mesh) { shadow_mesh->shadow_owners.erase(mesh); } mesh->shadow_mesh = p_shadow_mesh; - shadow_mesh = mesh_owner.getornull(mesh->shadow_mesh); + shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh); if (shadow_mesh) { shadow_mesh->shadow_owners.insert(mesh); @@ -2987,7 +3552,7 @@ void RendererStorageRD::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) { } void RendererStorageRD::mesh_clear(RID p_mesh) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND(!mesh); for (uint32_t i = 0; i < mesh->surface_count; i++) { Mesh::Surface &s = *mesh->surfaces[i]; @@ -3041,7 +3606,7 @@ void RendererStorageRD::mesh_clear(RID p_mesh) { } bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, false); return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton); @@ -3050,11 +3615,11 @@ bool RendererStorageRD::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) { /* MESH INSTANCE */ RID RendererStorageRD::mesh_instance_create(RID p_base) { - Mesh *mesh = mesh_owner.getornull(p_base); + Mesh *mesh = mesh_owner.get_or_null(p_base); ERR_FAIL_COND_V(!mesh, RID()); RID rid = mesh_instance_owner.make_rid(); - MeshInstance *mi = mesh_instance_owner.getornull(rid); + MeshInstance *mi = mesh_instance_owner.get_or_null(rid); mi->mesh = mesh; @@ -3069,7 +3634,7 @@ RID RendererStorageRD::mesh_instance_create(RID p_base) { return rid; } void RendererStorageRD::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton) { - MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); if (mi->skeleton == p_skeleton) { return; } @@ -3079,7 +3644,7 @@ void RendererStorageRD::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_sk } void RendererStorageRD::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) { - MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); ERR_FAIL_COND(!mi); ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size()); mi->blend_weights[p_shape] = p_weight; @@ -3151,7 +3716,7 @@ void RendererStorageRD::_mesh_instance_add_surface(MeshInstance *mi, Mesh *mesh, } void RendererStorageRD::mesh_instance_check_for_update(RID p_mesh_instance) { - MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); bool needs_update = mi->dirty; @@ -3165,7 +3730,7 @@ void RendererStorageRD::mesh_instance_check_for_update(RID p_mesh_instance) { } if (!needs_update && mi->skeleton.is_valid()) { - Skeleton *sk = skeleton_owner.getornull(mi->skeleton); + Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton); if (sk && sk->version != mi->skeleton_version) { needs_update = true; } @@ -3196,7 +3761,7 @@ void RendererStorageRD::update_mesh_instances() { while (dirty_mesh_instance_arrays.first()) { MeshInstance *mi = dirty_mesh_instance_arrays.first()->self(); - Skeleton *sk = skeleton_owner.getornull(mi->skeleton); + Skeleton *sk = skeleton_owner.get_or_null(mi->skeleton); for (uint32_t i = 0; i < mi->surfaces.size(); i++) { if (mi->surfaces[i].uniform_set == RID() || mi->mesh->surfaces[i]->uniform_set == RID()) { @@ -3443,7 +4008,7 @@ void RendererStorageRD::multimesh_initialize(RID p_rid) { } void RendererStorageRD::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) { @@ -3486,13 +4051,13 @@ void RendererStorageRD::multimesh_allocate_data(RID p_multimesh, int p_instances } int RendererStorageRD::multimesh_get_instance_count(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, 0); return multimesh->instances; } void RendererStorageRD::multimesh_set_mesh(RID p_multimesh, RID p_mesh) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); if (multimesh->mesh == p_mesh) { return; @@ -3539,7 +4104,7 @@ void RendererStorageRD::_multimesh_make_local(MultiMesh *multimesh) const { memcpy(w, r, buffer.size()); } } else { - memset(w, 0, multimesh->instances * multimesh->stride_cache * sizeof(float)); + memset(w, 0, (size_t)multimesh->instances * multimesh->stride_cache * sizeof(float)); } } uint32_t data_cache_dirty_region_count = (multimesh->instances - 1) / MULTIMESH_DIRTY_REGION_SIZE + 1; @@ -3638,7 +4203,7 @@ void RendererStorageRD::_multimesh_re_create_aabb(MultiMesh *multimesh, const fl } void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D); @@ -3668,7 +4233,7 @@ void RendererStorageRD::multimesh_instance_set_transform(RID p_multimesh, int p_ } void RendererStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D); @@ -3694,7 +4259,7 @@ void RendererStorageRD::multimesh_instance_set_transform_2d(RID p_multimesh, int } void RendererStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); ERR_FAIL_COND(!multimesh->uses_colors); @@ -3716,7 +4281,7 @@ void RendererStorageRD::multimesh_instance_set_color(RID p_multimesh, int p_inde } void RendererStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_INDEX(p_index, multimesh->instances); ERR_FAIL_COND(!multimesh->uses_custom_data); @@ -3738,14 +4303,14 @@ void RendererStorageRD::multimesh_instance_set_custom_data(RID p_multimesh, int } RID RendererStorageRD::multimesh_get_mesh(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, RID()); return multimesh->mesh; } Transform3D RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, int p_index) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, Transform3D()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D()); ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform3D()); @@ -3776,7 +4341,7 @@ Transform3D RendererStorageRD::multimesh_instance_get_transform(RID p_multimesh, } Transform2D RendererStorageRD::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, Transform2D()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D()); ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D, Transform2D()); @@ -3801,7 +4366,7 @@ Transform2D RendererStorageRD::multimesh_instance_get_transform_2d(RID p_multime } Color RendererStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_index) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, Color()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color()); ERR_FAIL_COND_V(!multimesh->uses_colors, Color()); @@ -3824,7 +4389,7 @@ Color RendererStorageRD::multimesh_instance_get_color(RID p_multimesh, int p_ind } Color RendererStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, Color()); ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color()); ERR_FAIL_COND_V(!multimesh->uses_custom_data, Color()); @@ -3847,7 +4412,7 @@ Color RendererStorageRD::multimesh_instance_get_custom_data(RID p_multimesh, int } void RendererStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_COND(p_buffer.size() != (multimesh->instances * (int)multimesh->stride_cache)); @@ -3880,7 +4445,7 @@ void RendererStorageRD::multimesh_set_buffer(RID p_multimesh, const Vector<float } Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, Vector<float>()); if (multimesh->buffer.is_null()) { return Vector<float>(); @@ -3903,7 +4468,7 @@ Vector<float> RendererStorageRD::multimesh_get_buffer(RID p_multimesh) const { } void RendererStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_visible) { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND(!multimesh); ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances); if (multimesh->visible_instances == p_visible) { @@ -3921,13 +4486,13 @@ void RendererStorageRD::multimesh_set_visible_instances(RID p_multimesh, int p_v } int RendererStorageRD::multimesh_get_visible_instances(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, 0); return multimesh->visible_instances; } AABB RendererStorageRD::multimesh_get_aabb(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); ERR_FAIL_COND_V(!multimesh, AABB()); if (multimesh->aabb_dirty) { const_cast<RendererStorageRD *>(this)->_update_dirty_multimeshes(); @@ -3952,14 +4517,15 @@ void RendererStorageRD::_update_dirty_multimeshes() { if (multimesh->data_cache_used_dirty_regions > 32 || multimesh->data_cache_used_dirty_regions > visible_region_count / 2) { //if there too many dirty regions, or represent the majority of regions, just copy all, else transfer cost piles up too much - RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * multimesh->stride_cache * sizeof(float)), data); + RD::get_singleton()->buffer_update(multimesh->buffer, 0, MIN(visible_region_count * region_size, multimesh->instances * (uint32_t)multimesh->stride_cache * (uint32_t)sizeof(float)), data); } else { //not that many regions? update them all for (uint32_t i = 0; i < visible_region_count; i++) { if (multimesh->data_cache_dirty_regions[i]) { - uint64_t offset = i * region_size; - uint64_t size = multimesh->stride_cache * multimesh->instances * sizeof(float); - RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[i * region_size]); + uint32_t offset = i * region_size; + uint32_t size = multimesh->stride_cache * (uint32_t)multimesh->instances * (uint32_t)sizeof(float); + uint32_t region_start_index = multimesh->stride_cache * MULTIMESH_DIRTY_REGION_SIZE * i; + RD::get_singleton()->buffer_update(multimesh->buffer, offset, MIN(region_size, size - offset), &data[region_start_index]); } } } @@ -3998,7 +4564,7 @@ void RendererStorageRD::particles_initialize(RID p_rid) { } void RendererStorageRD::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); if (particles->mode == p_mode) { return; @@ -4010,7 +4576,7 @@ void RendererStorageRD::particles_set_mode(RID p_particles, RS::ParticlesMode p_ } void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->emitting = p_emitting; @@ -4018,7 +4584,7 @@ void RendererStorageRD::particles_set_emitting(RID p_particles, bool p_emitting) bool RendererStorageRD::particles_get_emitting(RID p_particles) { ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, false); return particles->emitting; @@ -4073,7 +4639,7 @@ void RendererStorageRD::_particles_free_data(Particles *particles) { } void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); if (particles->amount == p_amount) { @@ -4093,55 +4659,56 @@ void RendererStorageRD::particles_set_amount(RID p_particles, int p_amount) { } void RendererStorageRD::particles_set_lifetime(RID p_particles, double p_lifetime) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->lifetime = p_lifetime; } void RendererStorageRD::particles_set_one_shot(RID p_particles, bool p_one_shot) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->one_shot = p_one_shot; } void RendererStorageRD::particles_set_pre_process_time(RID p_particles, double p_time) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->pre_process_time = p_time; } void RendererStorageRD::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->explosiveness = p_ratio; } void RendererStorageRD::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->randomness = p_ratio; } void RendererStorageRD::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->custom_aabb = p_aabb; particles->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::particles_set_speed_scale(RID p_particles, double p_scale) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->speed_scale = p_scale; } void RendererStorageRD::particles_set_use_local_coordinates(RID p_particles, bool p_enable) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->use_local_coords = p_enable; + particles->dependency.changed_notify(DEPENDENCY_CHANGED_PARTICLES); } void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->fixed_fps = p_fps; @@ -4157,21 +4724,21 @@ void RendererStorageRD::particles_set_fixed_fps(RID p_particles, int p_fps) { } void RendererStorageRD::particles_set_interpolate(RID p_particles, bool p_enable) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->interpolate = p_enable; } void RendererStorageRD::particles_set_fractional_delta(RID p_particles, bool p_enable) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->fractional_delta = p_enable; } void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, double p_length) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_COND(p_length < 0.1); p_length = MIN(10.0, p_length); @@ -4190,7 +4757,7 @@ void RendererStorageRD::particles_set_trails(RID p_particles, bool p_enable, dou } void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Vector<Transform3D> &p_bind_poses) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); if (particles->trail_bind_pose_buffer.is_valid() && particles->trail_bind_poses.size() != p_bind_poses.size()) { _particles_free_data(particles); @@ -4207,49 +4774,49 @@ void RendererStorageRD::particles_set_trail_bind_poses(RID p_particles, const Ve } void RendererStorageRD::particles_set_collision_base_size(RID p_particles, real_t p_size) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->collision_base_size = p_size; } void RendererStorageRD::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->transform_align = p_transform_align; } void RendererStorageRD::particles_set_process_material(RID p_particles, RID p_material) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->process_material = p_material; } void RendererStorageRD::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->draw_order = p_order; } void RendererStorageRD::particles_set_draw_passes(RID p_particles, int p_passes) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->draw_passes.resize(p_passes); } void RendererStorageRD::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_INDEX(p_pass, particles->draw_passes.size()); particles->draw_passes.write[p_pass] = p_mesh; } void RendererStorageRD::particles_restart(RID p_particles) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->restart_request = true; @@ -4273,7 +4840,7 @@ void RendererStorageRD::_particles_allocate_emission_buffer(Particles *particles } void RendererStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitter_particles) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_COND(p_particles == p_subemitter_particles); @@ -4286,7 +4853,7 @@ void RendererStorageRD::particles_set_subemitter(RID p_particles, RID p_subemitt } void RendererStorageRD::particles_emit(RID p_particles, const Transform3D &p_transform, const Vector3 &p_velocity, const Color &p_color, const Color &p_custom, uint32_t p_emit_flags) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); ERR_FAIL_COND(particles->amount == 0); @@ -4329,7 +4896,7 @@ void RendererStorageRD::particles_emit(RID p_particles, const Transform3D &p_tra } void RendererStorageRD::particles_request_process(RID p_particles) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); if (!particles->dirty) { @@ -4344,7 +4911,7 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { WARN_PRINT_ONCE("Calling this function with threaded rendering enabled stalls the renderer, use with care."); } - const Particles *particles = particles_owner.getornull(p_particles); + const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, AABB()); int total_amount = particles->amount; @@ -4352,10 +4919,8 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { total_amount *= particles->trail_bind_poses.size(); } - Vector<ParticleData> data; - data.resize(total_amount); - Vector<uint8_t> buffer = RD::get_singleton()->buffer_get_data(particles->particle_buffer); + ERR_FAIL_COND_V(buffer.size() != (int)(total_amount * sizeof(ParticleData)), AABB()); Transform3D inv = particles->emission_transform.affine_inverse(); @@ -4363,7 +4928,7 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { if (buffer.size()) { bool first = true; - const ParticleData *particle_data = (const ParticleData *)data.ptr(); + const ParticleData *particle_data = reinterpret_cast<const ParticleData *>(buffer.ptr()); for (int i = 0; i < total_amount; i++) { if (particle_data[i].active) { Vector3 pos = Vector3(particle_data[i].xform[12], particle_data[i].xform[13], particle_data[i].xform[14]); @@ -4394,28 +4959,28 @@ AABB RendererStorageRD::particles_get_current_aabb(RID p_particles) { } AABB RendererStorageRD::particles_get_aabb(RID p_particles) const { - const Particles *particles = particles_owner.getornull(p_particles); + const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, AABB()); return particles->custom_aabb; } void RendererStorageRD::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->emission_transform = p_transform; } int RendererStorageRD::particles_get_draw_passes(RID p_particles) const { - const Particles *particles = particles_owner.getornull(p_particles); + const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, 0); return particles->draw_passes.size(); } RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { - const Particles *particles = particles_owner.getornull(p_particles); + const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, RID()); ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID()); @@ -4423,19 +4988,19 @@ RID RendererStorageRD::particles_get_draw_pass_mesh(RID p_particles, int p_pass) } void RendererStorageRD::particles_add_collision(RID p_particles, RID p_particles_collision_instance) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->collisions.insert(p_particles_collision_instance); } void RendererStorageRD::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->collisions.erase(p_particles_collision_instance); } void RendererStorageRD::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, RID p_texture) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); particles->has_sdf_collision = p_enable; particles->sdf_collision_transform = p_xform; @@ -4477,7 +5042,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, double p_delt RD::Uniform u; u.uniform_type = RD::UNIFORM_TYPE_STORAGE_BUFFER; u.binding = 3; - Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter); + Particles *sub_emitter = particles_owner.get_or_null(p_particles->sub_emitter); if (sub_emitter) { if (sub_emitter->emission_buffer == nullptr) { //no emission buffer, allocate emission buffer _particles_allocate_emission_buffer(sub_emitter); @@ -4594,11 +5159,11 @@ void RendererStorageRD::_particles_process(Particles *p_particles, double p_delt uint32_t collision_3d_textures_used = 0; for (const Set<RID>::Element *E = p_particles->collisions.front(); E; E = E->next()) { - ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(E->get()); + ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(E->get()); if (!pci || !pci->active) { continue; } - ParticlesCollision *pc = particles_collision_owner.getornull(pci->collision); + ParticlesCollision *pc = particles_collision_owner.get_or_null(pci->collision); ERR_CONTINUE(!pc); Transform3D to_collider = pci->transform; @@ -4746,7 +5311,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, double p_delt for (uint32_t i = 0; i < ParticlesFrameParams::MAX_3D_TEXTURES; i++) { RID rd_tex; if (i < collision_3d_textures_used) { - Texture *t = texture_owner.getornull(collision_3d_textures[i]); + Texture *t = texture_owner.get_or_null(collision_3d_textures[i]); if (t && t->type == Texture::TYPE_3D) { rd_tex = t->rd_texture; } @@ -4791,7 +5356,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, double p_delt p_particles->force_sub_emit = false; //reset - Particles *sub_emitter = particles_owner.getornull(p_particles->sub_emitter); + Particles *sub_emitter = particles_owner.get_or_null(p_particles->sub_emitter); if (sub_emitter && sub_emitter->emission_storage_buffer.is_valid()) { // print_line("updating subemitter buffer"); @@ -4871,7 +5436,7 @@ void RendererStorageRD::_particles_process(Particles *p_particles, double p_delt } void RendererStorageRD::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND(!particles); if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) { @@ -5229,7 +5794,7 @@ void RendererStorageRD::update_particles() { bool RendererStorageRD::particles_is_inactive(RID p_particles) const { ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer."); - const Particles *particles = particles_owner.getornull(p_particles); + const Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, false); return !particles->emitting && particles->inactive; } @@ -5288,47 +5853,56 @@ void RendererStorageRD::ParticlesShaderData::set_code(const String &p_code) { valid = true; } -void RendererStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture) { +void RendererStorageRD::ParticlesShaderData::set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) { if (!p_texture.is_valid()) { - default_texture_params.erase(p_name); + if (default_texture_params.has(p_name) && default_texture_params[p_name].has(p_index)) { + default_texture_params[p_name].erase(p_index); + + if (default_texture_params[p_name].is_empty()) { + default_texture_params.erase(p_name); + } + } } else { - default_texture_params[p_name] = p_texture; + if (!default_texture_params.has(p_name)) { + default_texture_params[p_name] = Map<int, RID>(); + } + default_texture_params[p_name][p_index] = p_texture; } } void RendererStorageRD::ParticlesShaderData::get_param_list(List<PropertyInfo> *p_param_list) const { Map<int, StringName> order; - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E->get().scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL || E.value.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } - if (E->get().texture_order >= 0) { - order[E->get().texture_order + 100000] = E->key(); + if (E.value.texture_order >= 0) { + order[E.value.texture_order + 100000] = E.key; } else { - order[E->get().order] = E->key(); + order[E.value.order] = E.key; } } - for (Map<int, StringName>::Element *E = order.front(); E; E = E->next()) { - PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E->get()]); - pi.name = E->get(); + for (const KeyValue<int, StringName> &E : order) { + PropertyInfo pi = ShaderLanguage::uniform_to_property_info(uniforms[E.value]); + pi.name = E.value; p_param_list->push_back(pi); } } void RendererStorageRD::ParticlesShaderData::get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const { - for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = uniforms.front(); E; E = E->next()) { - if (E->get().scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + for (const KeyValue<StringName, ShaderLanguage::ShaderNode::Uniform> &E : uniforms) { + if (E.value.scope != ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; } RendererStorage::InstanceShaderParam p; - p.info = ShaderLanguage::uniform_to_property_info(E->get()); - p.info.name = E->key(); //supply name - p.index = E->get().instance_index; - p.default_value = ShaderLanguage::constant_value_to_variant(E->get().default_value, E->get().type, E->get().hint); + p.info = ShaderLanguage::uniform_to_property_info(E.value); + p.info.name = E.key; //supply name + p.index = E.value.instance_index; + p.default_value = ShaderLanguage::constant_value_to_variant(E.value.default_value, E.value.type, E.value.array_size, E.value.hint); p_param_list->push_back(p); } } @@ -5353,7 +5927,7 @@ Variant RendererStorageRD::ParticlesShaderData::get_default_parameter(const Stri if (uniforms.has(p_parameter)) { ShaderLanguage::ShaderNode::Uniform uniform = uniforms[p_parameter]; Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; - return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.array_size, uniform.hint); } return Variant(); } @@ -5407,7 +5981,7 @@ void RendererStorageRD::particles_collision_initialize(RID p_rid) { } RID RendererStorageRD::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, RID()); ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, RID()); @@ -5442,7 +6016,7 @@ RID RendererStorageRD::particles_collision_get_heightfield_framebuffer(RID p_par } void RendererStorageRD::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); if (p_type == particles_collision->type) { @@ -5458,13 +6032,13 @@ void RendererStorageRD::particles_collision_set_collision_type(RID p_particles_c } void RendererStorageRD::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->cull_mask = p_cull_mask; } void RendererStorageRD::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->radius = p_radius; @@ -5472,7 +6046,7 @@ void RendererStorageRD::particles_collision_set_sphere_radius(RID p_particles_co } void RendererStorageRD::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->extents = p_extents; @@ -5480,41 +6054,41 @@ void RendererStorageRD::particles_collision_set_box_extents(RID p_particles_coll } void RendererStorageRD::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_strength = p_strength; } void RendererStorageRD::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_directionality = p_directionality; } void RendererStorageRD::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->attractor_attenuation = p_curve; } void RendererStorageRD::particles_collision_set_field_texture(RID p_particles_collision, RID p_texture) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->field_texture = p_texture; } void RendererStorageRD::particles_collision_height_field_update(RID p_particles_collision) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); particles_collision->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND(!particles_collision); ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX); @@ -5531,7 +6105,7 @@ void RendererStorageRD::particles_collision_set_height_field_resolution(RID p_pa } AABB RendererStorageRD::particles_collision_get_aabb(RID p_particles_collision) const { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, AABB()); switch (particles_collision->type) { @@ -5554,13 +6128,13 @@ AABB RendererStorageRD::particles_collision_get_aabb(RID p_particles_collision) } Vector3 RendererStorageRD::particles_collision_get_extents(RID p_particles_collision) const { - const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, Vector3()); return particles_collision->extents; } bool RendererStorageRD::particles_collision_is_heightfield(RID p_particles_collision) const { - const ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_particles_collision); + const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision); ERR_FAIL_COND_V(!particles_collision, false); return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE; } @@ -5571,16 +6145,92 @@ RID RendererStorageRD::particles_collision_instance_create(RID p_collision) { return particles_collision_instance_owner.make_rid(pci); } void RendererStorageRD::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) { - ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); + ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance); ERR_FAIL_COND(!pci); pci->transform = p_transform; } void RendererStorageRD::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) { - ParticlesCollisionInstance *pci = particles_collision_instance_owner.getornull(p_collision_instance); + ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance); ERR_FAIL_COND(!pci); pci->active = p_active; } +/* FOG VOLUMES */ + +RID RendererStorageRD::fog_volume_allocate() { + return fog_volume_owner.allocate_rid(); +} +void RendererStorageRD::fog_volume_initialize(RID p_rid) { + fog_volume_owner.initialize_rid(p_rid, FogVolume()); +} + +void RendererStorageRD::fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) { + FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); + ERR_FAIL_COND(!fog_volume); + + if (p_shape == fog_volume->shape) { + return; + } + + fog_volume->shape = p_shape; + fog_volume->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); +} + +void RendererStorageRD::fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) { + FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); + ERR_FAIL_COND(!fog_volume); + + fog_volume->extents = p_extents; + fog_volume->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); +} + +void RendererStorageRD::fog_volume_set_material(RID p_fog_volume, RID p_material) { + FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); + ERR_FAIL_COND(!fog_volume); + fog_volume->material = p_material; +} + +RID RendererStorageRD::fog_volume_get_material(RID p_fog_volume) const { + FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); + ERR_FAIL_COND_V(!fog_volume, RID()); + + return fog_volume->material; +} + +RS::FogVolumeShape RendererStorageRD::fog_volume_get_shape(RID p_fog_volume) const { + FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); + ERR_FAIL_COND_V(!fog_volume, RS::FOG_VOLUME_SHAPE_BOX); + + return fog_volume->shape; +} + +AABB RendererStorageRD::fog_volume_get_aabb(RID p_fog_volume) const { + FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); + ERR_FAIL_COND_V(!fog_volume, AABB()); + + switch (fog_volume->shape) { + case RS::FOG_VOLUME_SHAPE_ELLIPSOID: + case RS::FOG_VOLUME_SHAPE_BOX: { + AABB aabb; + aabb.position = -fog_volume->extents; + aabb.size = fog_volume->extents * 2; + return aabb; + } + default: { + // Need some size otherwise will get culled + return AABB(Vector3(-1, -1, -1), Vector3(2, 2, 2)); + } + } + + return AABB(); +} + +Vector3 RendererStorageRD::fog_volume_get_extents(RID p_fog_volume) const { + const FogVolume *fog_volume = fog_volume_owner.get_or_null(p_fog_volume); + ERR_FAIL_COND_V(!fog_volume, Vector3()); + return fog_volume->extents; +} + /* VISIBILITY NOTIFIER */ RID RendererStorageRD::visibility_notifier_allocate() { @@ -5590,25 +6240,25 @@ void RendererStorageRD::visibility_notifier_initialize(RID p_notifier) { visibility_notifier_owner.initialize_rid(p_notifier, VisibilityNotifier()); } void RendererStorageRD::visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) { - VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier); ERR_FAIL_COND(!vn); vn->aabb = p_aabb; vn->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::visibility_notifier_set_callbacks(RID p_notifier, const Callable &p_enter_callbable, const Callable &p_exit_callable) { - VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier); ERR_FAIL_COND(!vn); vn->enter_callback = p_enter_callbable; vn->exit_callback = p_exit_callable; } AABB RendererStorageRD::visibility_notifier_get_aabb(RID p_notifier) const { - const VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + const VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier); ERR_FAIL_COND_V(!vn, AABB()); return vn->aabb; } void RendererStorageRD::visibility_notifier_call(RID p_notifier, bool p_enter, bool p_deferred) { - VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_notifier); + VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_notifier); ERR_FAIL_COND(!vn); if (p_enter) { @@ -5652,7 +6302,7 @@ void RendererStorageRD::_skeleton_make_dirty(Skeleton *skeleton) { } void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND(!skeleton); ERR_FAIL_COND(p_bones < 0); @@ -5695,14 +6345,14 @@ void RendererStorageRD::skeleton_allocate_data(RID p_skeleton, int p_bones, bool } int RendererStorageRD::skeleton_get_bone_count(RID p_skeleton) const { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND_V(!skeleton, 0); return skeleton->size; } void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND(!skeleton); ERR_FAIL_INDEX(p_bone, skeleton->size); @@ -5727,7 +6377,7 @@ void RendererStorageRD::skeleton_bone_set_transform(RID p_skeleton, int p_bone, } Transform3D RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND_V(!skeleton, Transform3D()); ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform3D()); @@ -5754,7 +6404,7 @@ Transform3D RendererStorageRD::skeleton_bone_get_transform(RID p_skeleton, int p } void RendererStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND(!skeleton); ERR_FAIL_INDEX(p_bone, skeleton->size); @@ -5775,7 +6425,7 @@ void RendererStorageRD::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bon } Transform2D RendererStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND_V(!skeleton, Transform2D()); ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D()); @@ -5795,7 +6445,7 @@ Transform2D RendererStorageRD::skeleton_bone_get_transform_2d(RID p_skeleton, in } void RendererStorageRD::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND(!skeleton->use_2d); @@ -5874,14 +6524,14 @@ void RendererStorageRD::spot_light_initialize(RID p_light) { } void RendererStorageRD::light_set_color(RID p_light, const Color &p_color) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->color = p_color; } void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, float p_value) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX); @@ -5916,7 +6566,7 @@ void RendererStorageRD::light_set_param(RID p_light, RS::LightParam p_param, flo } void RendererStorageRD::light_set_shadow(RID p_light, bool p_enabled) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->shadow = p_enabled; @@ -5925,13 +6575,13 @@ void RendererStorageRD::light_set_shadow(RID p_light, bool p_enabled) { } void RendererStorageRD::light_set_shadow_color(RID p_light, const Color &p_color) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->shadow_color = p_color; } void RendererStorageRD::light_set_projector(RID p_light, RID p_texture) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); if (light->projector == p_texture) { @@ -5953,14 +6603,14 @@ void RendererStorageRD::light_set_projector(RID p_light, RID p_texture) { } void RendererStorageRD::light_set_negative(RID p_light, bool p_enable) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->negative = p_enable; } void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->cull_mask = p_mask; @@ -5970,7 +6620,7 @@ void RendererStorageRD::light_set_cull_mask(RID p_light, uint32_t p_mask) { } void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->reverse_cull = p_enabled; @@ -5980,7 +6630,7 @@ void RendererStorageRD::light_set_reverse_cull_face_mode(RID p_light, bool p_ena } void RendererStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->bake_mode = p_bake_mode; @@ -5990,7 +6640,7 @@ void RendererStorageRD::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bak } void RendererStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_cascade) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->max_sdfgi_cascade = p_cascade; @@ -6000,7 +6650,7 @@ void RendererStorageRD::light_set_max_sdfgi_cascade(RID p_light, uint32_t p_casc } void RendererStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->omni_shadow_mode = p_mode; @@ -6010,14 +6660,14 @@ void RendererStorageRD::light_omni_set_shadow_mode(RID p_light, RS::LightOmniSha } RS::LightOmniShadowMode RendererStorageRD::light_omni_get_shadow_mode(RID p_light) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE); return light->omni_shadow_mode; } void RendererStorageRD::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->directional_shadow_mode = p_mode; @@ -6026,7 +6676,7 @@ void RendererStorageRD::light_directional_set_shadow_mode(RID p_light, RS::Light } void RendererStorageRD::light_directional_set_blend_splits(RID p_light, bool p_enable) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->directional_blend_splits = p_enable; @@ -6035,56 +6685,56 @@ void RendererStorageRD::light_directional_set_blend_splits(RID p_light, bool p_e } bool RendererStorageRD::light_directional_get_blend_splits(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, false); return light->directional_blend_splits; } void RendererStorageRD::light_directional_set_sky_only(RID p_light, bool p_sky_only) { - Light *light = light_owner.getornull(p_light); + Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND(!light); light->directional_sky_only = p_sky_only; } bool RendererStorageRD::light_directional_is_sky_only(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, false); return light->directional_sky_only; } RS::LightDirectionalShadowMode RendererStorageRD::light_directional_get_shadow_mode(RID p_light) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL); return light->directional_shadow_mode; } uint32_t RendererStorageRD::light_get_max_sdfgi_cascade(RID p_light) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, 0); return light->max_sdfgi_cascade; } RS::LightBakeMode RendererStorageRD::light_get_bake_mode(RID p_light) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_BAKE_DISABLED); return light->bake_mode; } uint64_t RendererStorageRD::light_get_version(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, 0); return light->version; } AABB RendererStorageRD::light_get_aabb(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, AABB()); switch (light->type) { @@ -6115,7 +6765,7 @@ void RendererStorageRD::reflection_probe_initialize(RID p_reflection_probe) { } void RendererStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::ReflectionProbeUpdateMode p_mode) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->update_mode = p_mode; @@ -6123,35 +6773,35 @@ void RendererStorageRD::reflection_probe_set_update_mode(RID p_probe, RS::Reflec } void RendererStorageRD::reflection_probe_set_intensity(RID p_probe, float p_intensity) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->intensity = p_intensity; } void RendererStorageRD::reflection_probe_set_ambient_mode(RID p_probe, RS::ReflectionProbeAmbientMode p_mode) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_mode = p_mode; } void RendererStorageRD::reflection_probe_set_ambient_color(RID p_probe, const Color &p_color) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_color = p_color; } void RendererStorageRD::reflection_probe_set_ambient_energy(RID p_probe, float p_energy) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->ambient_color_energy = p_energy; } void RendererStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_distance) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->max_distance = p_distance; @@ -6160,7 +6810,7 @@ void RendererStorageRD::reflection_probe_set_max_distance(RID p_probe, float p_d } void RendererStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); if (reflection_probe->extents == p_extents) { @@ -6171,7 +6821,7 @@ void RendererStorageRD::reflection_probe_set_extents(RID p_probe, const Vector3 } void RendererStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->origin_offset = p_offset; @@ -6179,7 +6829,7 @@ void RendererStorageRD::reflection_probe_set_origin_offset(RID p_probe, const Ve } void RendererStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->interior = p_enable; @@ -6187,14 +6837,14 @@ void RendererStorageRD::reflection_probe_set_as_interior(RID p_probe, bool p_ena } void RendererStorageRD::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->box_projection = p_enable; } void RendererStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->enable_shadows = p_enable; @@ -6202,7 +6852,7 @@ void RendererStorageRD::reflection_probe_set_enable_shadows(RID p_probe, bool p_ } void RendererStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->cull_mask = p_layers; @@ -6210,7 +6860,7 @@ void RendererStorageRD::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_l } void RendererStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resolution) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); ERR_FAIL_COND(p_resolution < 32); @@ -6218,7 +6868,7 @@ void RendererStorageRD::reflection_probe_set_resolution(RID p_probe, int p_resol } void RendererStorageRD::reflection_probe_set_lod_threshold(RID p_probe, float p_ratio) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND(!reflection_probe); reflection_probe->lod_threshold = p_ratio; @@ -6227,7 +6877,7 @@ void RendererStorageRD::reflection_probe_set_lod_threshold(RID p_probe, float p_ } AABB RendererStorageRD::reflection_probe_get_aabb(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, AABB()); AABB aabb; @@ -6238,96 +6888,96 @@ AABB RendererStorageRD::reflection_probe_get_aabb(RID p_probe) const { } RS::ReflectionProbeUpdateMode RendererStorageRD::reflection_probe_get_update_mode(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_UPDATE_ALWAYS); return reflection_probe->update_mode; } uint32_t RendererStorageRD::reflection_probe_get_cull_mask(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->cull_mask; } Vector3 RendererStorageRD::reflection_probe_get_extents(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, Vector3()); return reflection_probe->extents; } Vector3 RendererStorageRD::reflection_probe_get_origin_offset(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, Vector3()); return reflection_probe->origin_offset; } bool RendererStorageRD::reflection_probe_renders_shadows(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->enable_shadows; } float RendererStorageRD::reflection_probe_get_origin_max_distance(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->max_distance; } float RendererStorageRD::reflection_probe_get_lod_threshold(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->lod_threshold; } int RendererStorageRD::reflection_probe_get_resolution(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->resolution; } float RendererStorageRD::reflection_probe_get_intensity(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->intensity; } bool RendererStorageRD::reflection_probe_is_interior(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->interior; } bool RendererStorageRD::reflection_probe_is_box_projection(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, false); return reflection_probe->box_projection; } RS::ReflectionProbeAmbientMode RendererStorageRD::reflection_probe_get_ambient_mode(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, RS::REFLECTION_PROBE_AMBIENT_DISABLED); return reflection_probe->ambient_mode; } Color RendererStorageRD::reflection_probe_get_ambient_color(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, Color()); return reflection_probe->ambient_color; } float RendererStorageRD::reflection_probe_get_ambient_color_energy(RID p_probe) const { - const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + const ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_probe); ERR_FAIL_COND_V(!reflection_probe, 0); return reflection_probe->ambient_color_energy; @@ -6341,14 +6991,14 @@ void RendererStorageRD::decal_initialize(RID p_decal) { } void RendererStorageRD::decal_set_extents(RID p_decal, const Vector3 &p_extents) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->extents = p_extents; decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, RID p_texture) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); ERR_FAIL_INDEX(p_type, RS::DECAL_TEXTURE_MAX); @@ -6372,32 +7022,32 @@ void RendererStorageRD::decal_set_texture(RID p_decal, RS::DecalTexture p_type, } void RendererStorageRD::decal_set_emission_energy(RID p_decal, float p_energy) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->emission_energy = p_energy; } void RendererStorageRD::decal_set_albedo_mix(RID p_decal, float p_mix) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->albedo_mix = p_mix; } void RendererStorageRD::decal_set_modulate(RID p_decal, const Color &p_modulate) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->modulate = p_modulate; } void RendererStorageRD::decal_set_cull_mask(RID p_decal, uint32_t p_layers) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->cull_mask = p_layers; decal->dependency.changed_notify(DEPENDENCY_CHANGED_AABB); } void RendererStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, float p_begin, float p_length) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->distance_fade = p_enabled; decal->distance_fade_begin = p_begin; @@ -6405,20 +7055,20 @@ void RendererStorageRD::decal_set_distance_fade(RID p_decal, bool p_enabled, flo } void RendererStorageRD::decal_set_fade(RID p_decal, float p_above, float p_below) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->upper_fade = p_above; decal->lower_fade = p_below; } void RendererStorageRD::decal_set_normal_fade(RID p_decal, float p_fade) { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND(!decal); decal->normal_fade = p_fade; } AABB RendererStorageRD::decal_get_aabb(RID p_decal) const { - Decal *decal = decal_owner.getornull(p_decal); + Decal *decal = decal_owner.get_or_null(p_decal); ERR_FAIL_COND_V(!decal, AABB()); return AABB(-decal->extents, decal->extents * 2.0); @@ -6432,7 +7082,7 @@ void RendererStorageRD::voxel_gi_initialize(RID p_voxel_gi) { } void RendererStorageRD::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D &p_to_cell_xform, const AABB &p_aabb, const Vector3i &p_octree_size, const Vector<uint8_t> &p_octree_cells, const Vector<uint8_t> &p_data_cells, const Vector<uint8_t> &p_distance_field, const Vector<int> &p_level_counts) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); if (voxel_gi->octree_buffer.is_valid()) { @@ -6557,20 +7207,20 @@ void RendererStorageRD::voxel_gi_allocate_data(RID p_voxel_gi, const Transform3D } AABB RendererStorageRD::voxel_gi_get_bounds(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, AABB()); return voxel_gi->bounds; } Vector3i RendererStorageRD::voxel_gi_get_octree_size(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, Vector3i()); return voxel_gi->octree_size; } Vector<uint8_t> RendererStorageRD::voxel_gi_get_octree_cells(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>()); if (voxel_gi->octree_buffer.is_valid()) { @@ -6580,7 +7230,7 @@ Vector<uint8_t> RendererStorageRD::voxel_gi_get_octree_cells(RID p_voxel_gi) con } Vector<uint8_t> RendererStorageRD::voxel_gi_get_data_cells(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>()); if (voxel_gi->data_buffer.is_valid()) { @@ -6590,7 +7240,7 @@ Vector<uint8_t> RendererStorageRD::voxel_gi_get_data_cells(RID p_voxel_gi) const } Vector<uint8_t> RendererStorageRD::voxel_gi_get_distance_field(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, Vector<uint8_t>()); if (voxel_gi->data_buffer.is_valid()) { @@ -6600,21 +7250,21 @@ Vector<uint8_t> RendererStorageRD::voxel_gi_get_distance_field(RID p_voxel_gi) c } Vector<int> RendererStorageRD::voxel_gi_get_level_counts(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, Vector<int>()); return voxel_gi->level_counts; } Transform3D RendererStorageRD::voxel_gi_get_to_cell_xform(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, Transform3D()); return voxel_gi->to_cell_xform; } void RendererStorageRD::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->dynamic_range = p_range; @@ -6622,14 +7272,14 @@ void RendererStorageRD::voxel_gi_set_dynamic_range(RID p_voxel_gi, float p_range } float RendererStorageRD::voxel_gi_get_dynamic_range(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->dynamic_range; } void RendererStorageRD::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->propagation = p_range; @@ -6637,72 +7287,72 @@ void RendererStorageRD::voxel_gi_set_propagation(RID p_voxel_gi, float p_range) } float RendererStorageRD::voxel_gi_get_propagation(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->propagation; } void RendererStorageRD::voxel_gi_set_energy(RID p_voxel_gi, float p_energy) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->energy = p_energy; } float RendererStorageRD::voxel_gi_get_energy(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->energy; } void RendererStorageRD::voxel_gi_set_bias(RID p_voxel_gi, float p_bias) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->bias = p_bias; } float RendererStorageRD::voxel_gi_get_bias(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->bias; } void RendererStorageRD::voxel_gi_set_normal_bias(RID p_voxel_gi, float p_normal_bias) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->normal_bias = p_normal_bias; } float RendererStorageRD::voxel_gi_get_normal_bias(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->normal_bias; } void RendererStorageRD::voxel_gi_set_anisotropy_strength(RID p_voxel_gi, float p_strength) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->anisotropy_strength = p_strength; } float RendererStorageRD::voxel_gi_get_anisotropy_strength(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->anisotropy_strength; } void RendererStorageRD::voxel_gi_set_interior(RID p_voxel_gi, bool p_enable) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->interior = p_enable; } void RendererStorageRD::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enable) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND(!voxel_gi); voxel_gi->use_two_bounces = p_enable; @@ -6710,43 +7360,43 @@ void RendererStorageRD::voxel_gi_set_use_two_bounces(RID p_voxel_gi, bool p_enab } bool RendererStorageRD::voxel_gi_is_using_two_bounces(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, false); return voxel_gi->use_two_bounces; } bool RendererStorageRD::voxel_gi_is_interior(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->interior; } uint32_t RendererStorageRD::voxel_gi_get_version(RID p_voxel_gi) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->version; } uint32_t RendererStorageRD::voxel_gi_get_data_version(RID p_voxel_gi) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, 0); return voxel_gi->data_version; } RID RendererStorageRD::voxel_gi_get_octree_buffer(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, RID()); return voxel_gi->octree_buffer; } RID RendererStorageRD::voxel_gi_get_data_buffer(RID p_voxel_gi) const { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, RID()); return voxel_gi->data_buffer; } RID RendererStorageRD::voxel_gi_get_sdf_texture(RID p_voxel_gi) { - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_voxel_gi); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_voxel_gi); ERR_FAIL_COND_V(!voxel_gi, RID()); return voxel_gi->sdf_texture; @@ -6763,20 +7413,20 @@ void RendererStorageRD::lightmap_initialize(RID p_lightmap) { } void RendererStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool p_uses_spherical_haromics) { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND(!lm); lightmap_array_version++; //erase lightmap users if (lm->light_texture.is_valid()) { - Texture *t = texture_owner.getornull(lm->light_texture); + Texture *t = texture_owner.get_or_null(lm->light_texture); if (t) { t->lightmap_users.erase(p_lightmap); } } - Texture *t = texture_owner.getornull(p_light); + Texture *t = texture_owner.get_or_null(p_light); lm->light_texture = p_light; lm->uses_spherical_harmonics = p_uses_spherical_haromics; @@ -6811,19 +7461,19 @@ void RendererStorageRD::lightmap_set_textures(RID p_lightmap, RID p_light, bool } void RendererStorageRD::lightmap_set_probe_bounds(RID p_lightmap, const AABB &p_bounds) { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND(!lm); lm->bounds = p_bounds; } void RendererStorageRD::lightmap_set_probe_interior(RID p_lightmap, bool p_interior) { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND(!lm); lm->interior = p_interior; } void RendererStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const PackedVector3Array &p_points, const PackedColorArray &p_point_sh, const PackedInt32Array &p_tetrahedra, const PackedInt32Array &p_bsp_tree) { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND(!lm); if (p_points.size()) { @@ -6839,26 +7489,26 @@ void RendererStorageRD::lightmap_set_probe_capture_data(RID p_lightmap, const Pa } PackedVector3Array RendererStorageRD::lightmap_get_probe_capture_points(RID p_lightmap) const { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND_V(!lm, PackedVector3Array()); return lm->points; } PackedColorArray RendererStorageRD::lightmap_get_probe_capture_sh(RID p_lightmap) const { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND_V(!lm, PackedColorArray()); return lm->point_sh; } PackedInt32Array RendererStorageRD::lightmap_get_probe_capture_tetrahedra(RID p_lightmap) const { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND_V(!lm, PackedInt32Array()); return lm->tetrahedra; } PackedInt32Array RendererStorageRD::lightmap_get_probe_capture_bsp_tree(RID p_lightmap) const { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND_V(!lm, PackedInt32Array()); return lm->bsp_tree; } @@ -6868,7 +7518,7 @@ void RendererStorageRD::lightmap_set_probe_capture_update_speed(float p_speed) { } void RendererStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_point, Color *r_sh) { - Lightmap *lm = lightmap_owner.getornull(p_lightmap); + Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND(!lm); for (int i = 0; i < 9; i++) { @@ -6918,13 +7568,13 @@ void RendererStorageRD::lightmap_tap_sh_light(RID p_lightmap, const Vector3 &p_p } bool RendererStorageRD::lightmap_is_interior(RID p_lightmap) const { - const Lightmap *lm = lightmap_owner.getornull(p_lightmap); + const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND_V(!lm, false); return lm->interior; } AABB RendererStorageRD::lightmap_get_aabb(RID p_lightmap) const { - const Lightmap *lm = lightmap_owner.getornull(p_lightmap); + const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND_V(!lm, AABB()); return lm->bounds; } @@ -6964,7 +7614,7 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) { //create a placeholder until updated rt->texture = texture_allocate(); texture_2d_placeholder_initialize(rt->texture); - Texture *tex = texture_owner.getornull(rt->texture); + Texture *tex = texture_owner.get_or_null(rt->texture); tex->is_render_target = true; } @@ -7011,7 +7661,7 @@ void RendererStorageRD::_update_render_target(RenderTarget *rt) { { //update texture - Texture *tex = texture_owner.getornull(rt->texture); + Texture *tex = texture_owner.get_or_null(rt->texture); //free existing textures if (RD::get_singleton()->texture_is_valid(tex->rd_texture)) { @@ -7118,7 +7768,7 @@ void RendererStorageRD::render_target_set_position(RID p_render_target, int p_x, } void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); if (rt->size.x != p_width || rt->size.y != p_height || rt->view_count != p_view_count) { rt->size.x = p_width; @@ -7129,7 +7779,7 @@ void RendererStorageRD::render_target_set_size(RID p_render_target, int p_width, } RID RendererStorageRD::render_target_get_texture(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->texture; @@ -7139,53 +7789,53 @@ void RendererStorageRD::render_target_set_external_texture(RID p_render_target, } void RendererStorageRD::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); rt->flags[p_flag] = p_value; _update_render_target(rt); } bool RendererStorageRD::render_target_was_used(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, false); return rt->was_used; } void RendererStorageRD::render_target_set_as_unused(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); rt->was_used = false; } Size2 RendererStorageRD::render_target_get_size(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, Size2()); return rt->size; } RID RendererStorageRD::render_target_get_rd_framebuffer(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->framebuffer; } RID RendererStorageRD::render_target_get_rd_texture(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->color; } RID RendererStorageRD::render_target_get_rd_backbuffer(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->backbuffer; } RID RendererStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); if (!rt->backbuffer.is_valid()) { @@ -7196,32 +7846,32 @@ RID RendererStorageRD::render_target_get_rd_backbuffer_framebuffer(RID p_render_ } void RendererStorageRD::render_target_request_clear(RID p_render_target, const Color &p_clear_color) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); rt->clear_requested = true; rt->clear_color = p_clear_color; } bool RendererStorageRD::render_target_is_clear_requested(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, false); return rt->clear_requested; } Color RendererStorageRD::render_target_get_clear_request_color(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, Color()); return rt->clear_color; } void RendererStorageRD::render_target_disable_clear_request(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); rt->clear_requested = false; } void RendererStorageRD::render_target_do_clear_request(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); if (!rt->clear_requested) { return; @@ -7234,7 +7884,7 @@ void RendererStorageRD::render_target_do_clear_request(RID p_render_target) { } void RendererStorageRD::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) { return; @@ -7276,28 +7926,28 @@ Rect2i RendererStorageRD::_render_target_get_sdf_rect(const RenderTarget *rt) co } Rect2i RendererStorageRD::render_target_get_sdf_rect(RID p_render_target) const { - const RenderTarget *rt = render_target_owner.getornull(p_render_target); + const RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, Rect2i()); return _render_target_get_sdf_rect(rt); } void RendererStorageRD::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); rt->sdf_enabled = p_enabled; } bool RendererStorageRD::render_target_is_sdf_enabled(RID p_render_target) const { - const RenderTarget *rt = render_target_owner.getornull(p_render_target); + const RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, false); return rt->sdf_enabled; } RID RendererStorageRD::render_target_get_sdf_texture(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); if (rt->sdf_buffer_read.is_null()) { // no texture, create a dummy one for the 2D uniform set @@ -7432,7 +8082,7 @@ void RendererStorageRD::_render_target_clear_sdf(RenderTarget *rt) { } RID RendererStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); if (rt->sdf_buffer_write_fb.is_null()) { @@ -7442,7 +8092,7 @@ RID RendererStorageRD::render_target_get_sdf_framebuffer(RID p_render_target) { return rt->sdf_buffer_write_fb; } void RendererStorageRD::render_target_sdf_process(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); ERR_FAIL_COND(rt->sdf_buffer_write_fb.is_null()); @@ -7517,7 +8167,7 @@ void RendererStorageRD::render_target_sdf_process(RID p_render_target) { } void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { _create_render_target_backbuffer(rt); @@ -7557,7 +8207,7 @@ void RendererStorageRD::render_target_copy_to_back_buffer(RID p_render_target, c } void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { _create_render_target_backbuffer(rt); @@ -7578,7 +8228,7 @@ void RendererStorageRD::render_target_clear_back_buffer(RID p_render_target, con } void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); if (!rt->backbuffer.is_valid()) { _create_render_target_backbuffer(rt); @@ -7610,66 +8260,69 @@ void RendererStorageRD::render_target_gen_back_buffer_mipmaps(RID p_render_targe } RID RendererStorageRD::render_target_get_framebuffer_uniform_set(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->framebuffer_uniform_set; } RID RendererStorageRD::render_target_get_backbuffer_uniform_set(RID p_render_target) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND_V(!rt, RID()); return rt->backbuffer_uniform_set; } void RendererStorageRD::render_target_set_framebuffer_uniform_set(RID p_render_target, RID p_uniform_set) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); rt->framebuffer_uniform_set = p_uniform_set; } void RendererStorageRD::render_target_set_backbuffer_uniform_set(RID p_render_target, RID p_uniform_set) { - RenderTarget *rt = render_target_owner.getornull(p_render_target); + RenderTarget *rt = render_target_owner.get_or_null(p_render_target); ERR_FAIL_COND(!rt); rt->backbuffer_uniform_set = p_uniform_set; } void RendererStorageRD::base_update_dependency(RID p_base, DependencyTracker *p_instance) { if (mesh_owner.owns(p_base)) { - Mesh *mesh = mesh_owner.getornull(p_base); + Mesh *mesh = mesh_owner.get_or_null(p_base); p_instance->update_dependency(&mesh->dependency); } else if (multimesh_owner.owns(p_base)) { - MultiMesh *multimesh = multimesh_owner.getornull(p_base); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_base); p_instance->update_dependency(&multimesh->dependency); if (multimesh->mesh.is_valid()) { base_update_dependency(multimesh->mesh, p_instance); } } else if (reflection_probe_owner.owns(p_base)) { - ReflectionProbe *rp = reflection_probe_owner.getornull(p_base); + ReflectionProbe *rp = reflection_probe_owner.get_or_null(p_base); p_instance->update_dependency(&rp->dependency); } else if (decal_owner.owns(p_base)) { - Decal *decal = decal_owner.getornull(p_base); + Decal *decal = decal_owner.get_or_null(p_base); p_instance->update_dependency(&decal->dependency); } else if (voxel_gi_owner.owns(p_base)) { - VoxelGI *gip = voxel_gi_owner.getornull(p_base); + VoxelGI *gip = voxel_gi_owner.get_or_null(p_base); p_instance->update_dependency(&gip->dependency); } else if (lightmap_owner.owns(p_base)) { - Lightmap *lm = lightmap_owner.getornull(p_base); + Lightmap *lm = lightmap_owner.get_or_null(p_base); p_instance->update_dependency(&lm->dependency); } else if (light_owner.owns(p_base)) { - Light *l = light_owner.getornull(p_base); + Light *l = light_owner.get_or_null(p_base); p_instance->update_dependency(&l->dependency); } else if (particles_owner.owns(p_base)) { - Particles *p = particles_owner.getornull(p_base); + Particles *p = particles_owner.get_or_null(p_base); p_instance->update_dependency(&p->dependency); } else if (particles_collision_owner.owns(p_base)) { - ParticlesCollision *pc = particles_collision_owner.getornull(p_base); + ParticlesCollision *pc = particles_collision_owner.get_or_null(p_base); p_instance->update_dependency(&pc->dependency); + } else if (fog_volume_owner.owns(p_base)) { + FogVolume *fv = fog_volume_owner.get_or_null(p_base); + p_instance->update_dependency(&fv->dependency); } else if (visibility_notifier_owner.owns(p_base)) { - VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_base); + VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_base); p_instance->update_dependency(&vn->dependency); } } void RendererStorageRD::skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance) { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND(!skeleton); p_instance->update_dependency(&skeleton->dependency); @@ -7703,6 +8356,9 @@ RS::InstanceType RendererStorageRD::get_base_type(RID p_rid) const { if (particles_collision_owner.owns(p_rid)) { return RS::INSTANCE_PARTICLES_COLLISION; } + if (fog_volume_owner.owns(p_rid)) { + return RS::INSTANCE_FOG_VOLUME; + } if (visibility_notifier_owner.owns(p_rid)) { return RS::INSTANCE_VISIBLITY_NOTIFIER; } @@ -7775,7 +8431,7 @@ void RendererStorageRD::_update_decal_atlas() { while ((K = decal_atlas.textures.next(K))) { DecalAtlas::SortItem &si = itemsv.write[idx]; - Texture *src_tex = texture_owner.getornull(*K); + Texture *src_tex = texture_owner.get_or_null(*K); si.size.width = (src_tex->width / border) + 1; si.size.height = (src_tex->height / border) + 1; @@ -7924,7 +8580,7 @@ void RendererStorageRD::_update_decal_atlas() { const RID *K = nullptr; while ((K = decal_atlas.textures.next(K))) { DecalAtlas::Texture *t = decal_atlas.textures.getptr(*K); - Texture *src_tex = texture_owner.getornull(*K); + Texture *src_tex = texture_owner.get_or_null(*K); effects->copy_to_atlas_fb(src_tex->rd_texture, mm.fb, t->uv_rect, draw_list, false, t->panorama_to_dp_users > 0); } @@ -8340,7 +8996,7 @@ void RendererStorageRD::global_variable_set(const StringName &p_name, const Vari } else { //texture for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) { - Material *material = material_owner.getornull(E->get()); + Material *material = material_owner.get_or_null(E->get()); ERR_CONTINUE(!material); _material_queue_update(material, false, true); } @@ -8371,7 +9027,7 @@ void RendererStorageRD::global_variable_set_override(const StringName &p_name, c } else { //texture for (Set<RID>::Element *E = gv.texture_materials.front(); E; E = E->next()) { - Material *material = material_owner.getornull(E->get()); + Material *material = material_owner.get_or_null(E->get()); ERR_CONTINUE(!material); _material_queue_update(material, false, true); } @@ -8552,7 +9208,7 @@ void RendererStorageRD::global_variables_instance_update(RID p_instance, int p_i pos += p_index; - _fill_std140_variant_ubo_value(datatype, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer + _fill_std140_variant_ubo_value(datatype, 0, p_value, (uint8_t *)&global_variables.buffer_values[pos], true); //instances always use linear color in this renderer _global_variable_mark_buffer_dirty(pos, 1); } @@ -8582,7 +9238,7 @@ void RendererStorageRD::_update_global_variables() { // only happens in the case of a buffer variable added or removed, // so not often. for (const RID &E : global_variables.materials_using_buffer) { - Material *material = material_owner.getornull(E); + Material *material = material_owner.get_or_null(E); ERR_CONTINUE(!material); //wtf _material_queue_update(material, true, false); @@ -8595,7 +9251,7 @@ void RendererStorageRD::_update_global_variables() { // only happens in the case of a buffer variable added or removed, // so not often. for (const RID &E : global_variables.materials_using_texture) { - Material *material = material_owner.getornull(E); + Material *material = material_owner.get_or_null(E); ERR_CONTINUE(!material); //wtf _material_queue_update(material, false, true); @@ -8640,7 +9296,7 @@ bool RendererStorageRD::has_os_feature(const String &p_feature) const { bool RendererStorageRD::free(RID p_rid) { if (texture_owner.owns(p_rid)) { - Texture *t = texture_owner.getornull(p_rid); + Texture *t = texture_owner.get_or_null(p_rid); ERR_FAIL_COND_V(!t, false); ERR_FAIL_COND_V(t->is_render_target, false); @@ -8654,7 +9310,7 @@ bool RendererStorageRD::free(RID p_rid) { } if (t->is_proxy && t->proxy_to.is_valid()) { - Texture *proxy_to = texture_owner.getornull(t->proxy_to); + Texture *proxy_to = texture_owner.get_or_null(t->proxy_to); if (proxy_to) { proxy_to->proxies.erase(p_rid); } @@ -8666,7 +9322,7 @@ bool RendererStorageRD::free(RID p_rid) { } for (int i = 0; i < t->proxies.size(); i++) { - Texture *p = texture_owner.getornull(t->proxies[i]); + Texture *p = texture_owner.get_or_null(t->proxies[i]); ERR_CONTINUE(!p); p->proxy_to = RID(); p->rd_texture = RID(); @@ -8681,7 +9337,7 @@ bool RendererStorageRD::free(RID p_rid) { } else if (canvas_texture_owner.owns(p_rid)) { canvas_texture_owner.free(p_rid); } else if (shader_owner.owns(p_rid)) { - Shader *shader = shader_owner.getornull(p_rid); + Shader *shader = shader_owner.get_or_null(p_rid); //make material unreference this while (shader->owners.size()) { material_set_shader(shader->owners.front()->get()->self, RID()); @@ -8693,7 +9349,7 @@ bool RendererStorageRD::free(RID p_rid) { shader_owner.free(p_rid); } else if (material_owner.owns(p_rid)) { - Material *material = material_owner.getornull(p_rid); + Material *material = material_owner.get_or_null(p_rid); material_set_shader(p_rid, RID()); //clean up shader material->dependency.deleted_notify(p_rid); @@ -8701,7 +9357,7 @@ bool RendererStorageRD::free(RID p_rid) { } else if (mesh_owner.owns(p_rid)) { mesh_clear(p_rid); mesh_set_shadow_mesh(p_rid, RID()); - Mesh *mesh = mesh_owner.getornull(p_rid); + Mesh *mesh = mesh_owner.get_or_null(p_rid); mesh->dependency.deleted_notify(p_rid); if (mesh->instances.size()) { ERR_PRINT("deleting mesh with active instances"); @@ -8715,7 +9371,7 @@ bool RendererStorageRD::free(RID p_rid) { } mesh_owner.free(p_rid); } else if (mesh_instance_owner.owns(p_rid)) { - MeshInstance *mi = mesh_instance_owner.getornull(p_rid); + MeshInstance *mi = mesh_instance_owner.get_or_null(p_rid); _mesh_instance_clear(mi); mi->mesh->instances.erase(mi->I); mi->I = nullptr; @@ -8725,21 +9381,21 @@ bool RendererStorageRD::free(RID p_rid) { } else if (multimesh_owner.owns(p_rid)) { _update_dirty_multimeshes(); multimesh_allocate_data(p_rid, 0, RS::MULTIMESH_TRANSFORM_2D); - MultiMesh *multimesh = multimesh_owner.getornull(p_rid); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_rid); multimesh->dependency.deleted_notify(p_rid); multimesh_owner.free(p_rid); } else if (skeleton_owner.owns(p_rid)) { _update_dirty_skeletons(); skeleton_allocate_data(p_rid, 0); - Skeleton *skeleton = skeleton_owner.getornull(p_rid); + Skeleton *skeleton = skeleton_owner.get_or_null(p_rid); skeleton->dependency.deleted_notify(p_rid); skeleton_owner.free(p_rid); } else if (reflection_probe_owner.owns(p_rid)) { - ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_rid); + ReflectionProbe *reflection_probe = reflection_probe_owner.get_or_null(p_rid); reflection_probe->dependency.deleted_notify(p_rid); reflection_probe_owner.free(p_rid); } else if (decal_owner.owns(p_rid)) { - Decal *decal = decal_owner.getornull(p_rid); + Decal *decal = decal_owner.get_or_null(p_rid); for (int i = 0; i < RS::DECAL_TEXTURE_MAX; i++) { if (decal->textures[i].is_valid() && texture_owner.owns(decal->textures[i])) { texture_remove_from_decal_atlas(decal->textures[i]); @@ -8749,30 +9405,30 @@ bool RendererStorageRD::free(RID p_rid) { decal_owner.free(p_rid); } else if (voxel_gi_owner.owns(p_rid)) { voxel_gi_allocate_data(p_rid, Transform3D(), AABB(), Vector3i(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<uint8_t>(), Vector<int>()); //deallocate - VoxelGI *voxel_gi = voxel_gi_owner.getornull(p_rid); + VoxelGI *voxel_gi = voxel_gi_owner.get_or_null(p_rid); voxel_gi->dependency.deleted_notify(p_rid); voxel_gi_owner.free(p_rid); } else if (lightmap_owner.owns(p_rid)) { lightmap_set_textures(p_rid, RID(), false); - Lightmap *lightmap = lightmap_owner.getornull(p_rid); + Lightmap *lightmap = lightmap_owner.get_or_null(p_rid); lightmap->dependency.deleted_notify(p_rid); lightmap_owner.free(p_rid); } else if (light_owner.owns(p_rid)) { light_set_projector(p_rid, RID()); //clear projector // delete the texture - Light *light = light_owner.getornull(p_rid); + Light *light = light_owner.get_or_null(p_rid); light->dependency.deleted_notify(p_rid); light_owner.free(p_rid); } else if (particles_owner.owns(p_rid)) { update_particles(); - Particles *particles = particles_owner.getornull(p_rid); + Particles *particles = particles_owner.get_or_null(p_rid); particles->dependency.deleted_notify(p_rid); _particles_free_data(particles); particles_owner.free(p_rid); } else if (particles_collision_owner.owns(p_rid)) { - ParticlesCollision *particles_collision = particles_collision_owner.getornull(p_rid); + ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_rid); if (particles_collision->heightfield_texture.is_valid()) { RD::get_singleton()->free(particles_collision->heightfield_texture); @@ -8780,18 +9436,22 @@ bool RendererStorageRD::free(RID p_rid) { particles_collision->dependency.deleted_notify(p_rid); particles_collision_owner.free(p_rid); } else if (visibility_notifier_owner.owns(p_rid)) { - VisibilityNotifier *vn = visibility_notifier_owner.getornull(p_rid); + VisibilityNotifier *vn = visibility_notifier_owner.get_or_null(p_rid); vn->dependency.deleted_notify(p_rid); visibility_notifier_owner.free(p_rid); } else if (particles_collision_instance_owner.owns(p_rid)) { particles_collision_instance_owner.free(p_rid); + } else if (fog_volume_owner.owns(p_rid)) { + FogVolume *fog_volume = fog_volume_owner.get_or_null(p_rid); + fog_volume->dependency.deleted_notify(p_rid); + fog_volume_owner.free(p_rid); } else if (render_target_owner.owns(p_rid)) { - RenderTarget *rt = render_target_owner.getornull(p_rid); + RenderTarget *rt = render_target_owner.get_or_null(p_rid); _clear_render_target(rt); if (rt->texture.is_valid()) { - Texture *tex = texture_owner.getornull(rt->texture); + Texture *tex = texture_owner.get_or_null(rt->texture); tex->is_render_target = false; free(rt->texture); } @@ -9081,6 +9741,18 @@ RendererStorageRD::RendererStorageRD() { { Vector<Vector<uint8_t>> vpv; vpv.push_back(pv); + default_rd_textures[DEFAULT_RD_TEXTURE_3D_BLACK] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); + } + for (int i = 0; i < 64; i++) { + pv.set(i * 4 + 0, 255); + pv.set(i * 4 + 1, 255); + pv.set(i * 4 + 2, 255); + pv.set(i * 4 + 3, 255); + } + + { + Vector<Vector<uint8_t>> vpv; + vpv.push_back(pv); default_rd_textures[DEFAULT_RD_TEXTURE_3D_WHITE] = RD::get_singleton()->texture_create(tformat, RD::TextureView(), vpv); } } @@ -9196,6 +9868,9 @@ RendererStorageRD::RendererStorageRD() { } } + //custom sampler + sampler_rd_configure_custom(0.0f); + //default rd buffers { Vector<uint8_t> buffer; @@ -9526,6 +10201,15 @@ RendererStorageRD::~RendererStorageRD() { } } + //custom samplers + for (int i = 1; i < RS::CANVAS_ITEM_TEXTURE_FILTER_MAX; i++) { + for (int j = 0; j < RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX; j++) { + if (custom_rd_samplers[i][j].is_valid()) { + RD::get_singleton()->free(custom_rd_samplers[i][j]); + } + } + } + //def buffers for (int i = 0; i < DEFAULT_RD_BUFFER_MAX; i++) { RD::get_singleton()->free(mesh_default_rd_buffers[i]); @@ -9551,6 +10235,6 @@ RendererStorageRD::~RendererStorageRD() { if (effects) { memdelete(effects); - effects = NULL; + effects = nullptr; } } diff --git a/servers/rendering/renderer_rd/renderer_storage_rd.h b/servers/rendering/renderer_rd/renderer_storage_rd.h index 02395a884f..9a64480c3e 100644 --- a/servers/rendering/renderer_rd/renderer_storage_rd.h +++ b/servers/rendering/renderer_rd/renderer_storage_rd.h @@ -129,12 +129,13 @@ public: SHADER_TYPE_3D, SHADER_TYPE_PARTICLES, SHADER_TYPE_SKY, + SHADER_TYPE_FOG, SHADER_TYPE_MAX }; struct ShaderData { virtual void set_code(const String &p_Code) = 0; - virtual void set_default_texture_param(const StringName &p_name, RID p_texture) = 0; + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index) = 0; virtual void get_param_list(List<PropertyInfo> *p_param_list) const = 0; virtual void get_instance_param_list(List<InstanceShaderParam> *p_param_list) const = 0; @@ -151,7 +152,7 @@ public: struct MaterialData { void update_uniform_buffer(const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Map<StringName, Variant> &p_parameters, uint8_t *p_buffer, uint32_t p_buffer_size, bool p_use_linear_color); - void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, RID> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color); + void update_textures(const Map<StringName, Variant> &p_parameters, const Map<StringName, Map<int, RID>> &p_default_textures, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, RID *p_textures, bool p_use_linear_color); virtual void set_render_priority(int p_priority) = 0; virtual void set_next_pass(RID p_pass) = 0; @@ -159,7 +160,7 @@ public: virtual ~MaterialData(); //to be used internally by update_parameters, in the most common configuration of material parameters - bool update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, RID> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier = RD::BARRIER_MASK_ALL); + bool update_parameters_uniform_set(const Map<StringName, Variant> &p_parameters, bool p_uniform_dirty, bool p_textures_dirty, const Map<StringName, ShaderLanguage::ShaderNode::Uniform> &p_uniforms, const uint32_t *p_uniform_offsets, const Vector<ShaderCompilerRD::GeneratedCode::Texture> &p_texture_uniforms, const Map<StringName, Map<int, RID>> &p_default_texture_params, uint32_t p_ubo_size, RID &uniform_set, RID p_shader, uint32_t p_shader_uniform_set, uint32_t p_barrier = RD::BARRIER_MASK_ALL); void free_parameters_uniform_set(RID p_uniform_set); private: @@ -188,6 +189,7 @@ public: DEFAULT_RD_TEXTURE_CUBEMAP_ARRAY_BLACK, DEFAULT_RD_TEXTURE_CUBEMAP_WHITE, DEFAULT_RD_TEXTURE_3D_WHITE, + DEFAULT_RD_TEXTURE_3D_BLACK, DEFAULT_RD_TEXTURE_2D_ARRAY_WHITE, DEFAULT_RD_TEXTURE_2D_UINT, DEFAULT_RD_TEXTURE_MAX @@ -318,6 +320,7 @@ private: RID default_rd_textures[DEFAULT_RD_TEXTURE_MAX]; RID default_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; + RID custom_rd_samplers[RS::CANVAS_ITEM_TEXTURE_FILTER_MAX][RS::CANVAS_ITEM_TEXTURE_REPEAT_MAX]; RID default_rd_storage_buffer; /* DECAL ATLAS */ @@ -372,7 +375,7 @@ private: ShaderData *data; String code; ShaderType type; - Map<StringName, RID> default_texture_parameter; + Map<StringName, Map<int, RID>> default_texture_parameter; Set<Material *> owners; }; @@ -621,7 +624,6 @@ private: float color[4]; float custom[3]; float lifetime; - uint32_t pad[3]; }; struct ParticlesFrameParams { @@ -882,14 +884,14 @@ private: String path; String code; - Map<StringName, RID> default_texture_params; + Map<StringName, Map<int, RID>> default_texture_params; RID pipeline; bool uses_time; virtual void set_code(const String &p_Code); - virtual void set_default_texture_param(const StringName &p_name, RID p_texture); + virtual void set_default_texture_param(const StringName &p_name, RID p_texture, int p_index); virtual void get_param_list(List<PropertyInfo> *p_param_list) const; virtual void get_instance_param_list(List<RendererStorage::InstanceShaderParam> *p_param_list) const; virtual bool is_param_texture(const StringName &p_param) const; @@ -958,6 +960,19 @@ private: mutable RID_Owner<ParticlesCollisionInstance> particles_collision_instance_owner; + /* FOG VOLUMES */ + + struct FogVolume { + RID material; + Vector3 extents = Vector3(1, 1, 1); + + RS::FogVolumeShape shape = RS::FOG_VOLUME_SHAPE_BOX; + + Dependency dependency; + }; + + mutable RID_Owner<FogVolume, true> fog_volume_owner; + /* visibility_notifier */ struct VisibilityNotifier { @@ -1285,7 +1300,7 @@ private: void _update_global_variables(); /* EFFECTS */ - EffectsRD *effects = NULL; + EffectsRD *effects = nullptr; public: virtual bool can_create_resources_async() const; @@ -1351,7 +1366,7 @@ public: if (p_texture.is_null()) { return RID(); } - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); if (!tex) { return RID(); @@ -1363,7 +1378,7 @@ public: if (p_texture.is_null()) { return Size2i(); } - Texture *tex = texture_owner.getornull(p_texture); + Texture *tex = texture_owner.get_or_null(p_texture); if (!tex) { return Size2i(); @@ -1377,6 +1392,13 @@ public: _FORCE_INLINE_ RID sampler_rd_get_default(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) { return default_rd_samplers[p_filter][p_repeat]; } + _FORCE_INLINE_ RID sampler_rd_get_custom(RS::CanvasItemTextureFilter p_filter, RS::CanvasItemTextureRepeat p_repeat) { + return custom_rd_samplers[p_filter][p_repeat]; + } + + void sampler_rd_configure_custom(float mipmap_bias); + + void sampler_rd_set_default(float p_mipmap_bias); /* CANVAS TEXTURE API */ @@ -1400,8 +1422,8 @@ public: String shader_get_code(RID p_shader) const; void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const; - void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture); - RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const; + void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index); + RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const; Variant shader_get_param_default(RID p_shader, const StringName &p_param) const; void shader_set_data_request_function(ShaderType p_shader_type, ShaderDataRequestFunction p_function); @@ -1431,12 +1453,12 @@ public: void material_set_data_request_function(ShaderType p_shader_type, MaterialDataRequestFunction p_function); _FORCE_INLINE_ uint32_t material_get_shader_id(RID p_material) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); return material->shader_id; } _FORCE_INLINE_ MaterialData *material_get_data(RID p_material, ShaderType p_shader_type) { - Material *material = material_owner.getornull(p_material); + Material *material = material_owner.get_or_null(p_material); if (!material || material->shader_type != p_shader_type) { return nullptr; } else { @@ -1489,7 +1511,7 @@ public: virtual void update_mesh_instances(); _FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, nullptr); r_surface_count = mesh->surface_count; if (r_surface_count == 0) { @@ -1506,7 +1528,7 @@ public: } _FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, nullptr); ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr); @@ -1514,7 +1536,7 @@ public: } _FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); ERR_FAIL_COND_V(!mesh, RID()); return mesh->shadow_mesh; @@ -1600,7 +1622,7 @@ public: } _FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, RID &r_vertex_array_rd, RD::VertexFormatID &r_vertex_format) { - MeshInstance *mi = mesh_instance_owner.getornull(p_mesh_instance); + MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance); ERR_FAIL_COND(!mi); Mesh *mesh = mi->mesh; ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count); @@ -1641,7 +1663,7 @@ public: } _FORCE_INLINE_ uint32_t mesh_surface_get_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); Mesh::Surface *s = mesh->surfaces[p_surface_index]; if (s->render_pass != p_render_pass) { @@ -1654,7 +1676,7 @@ public: } _FORCE_INLINE_ uint32_t mesh_surface_get_multimesh_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); Mesh::Surface *s = mesh->surfaces[p_surface_index]; if (s->multimesh_render_pass != p_render_pass) { @@ -1667,7 +1689,7 @@ public: } _FORCE_INLINE_ uint32_t mesh_surface_get_particles_render_pass_index(RID p_mesh, uint32_t p_surface_index, uint64_t p_render_pass, uint32_t *r_index) { - Mesh *mesh = mesh_owner.getornull(p_mesh); + Mesh *mesh = mesh_owner.get_or_null(p_mesh); Mesh::Surface *s = mesh->surfaces[p_surface_index]; if (s->particles_render_pass != p_render_pass) { @@ -1709,22 +1731,22 @@ public: AABB multimesh_get_aabb(RID p_multimesh) const; _FORCE_INLINE_ RS::MultimeshTransformFormat multimesh_get_transform_format(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); return multimesh->xform_format; } _FORCE_INLINE_ bool multimesh_uses_colors(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); return multimesh->uses_colors; } _FORCE_INLINE_ bool multimesh_uses_custom_data(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); return multimesh->uses_custom_data; } _FORCE_INLINE_ uint32_t multimesh_get_instances_to_draw(RID p_multimesh) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); if (multimesh->visible_instances >= 0) { return multimesh->visible_instances; } @@ -1732,7 +1754,7 @@ public: } _FORCE_INLINE_ RID multimesh_get_3d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); if (!multimesh->uniform_set_3d.is_valid()) { Vector<RD::Uniform> uniforms; RD::Uniform u; @@ -1747,7 +1769,7 @@ public: } _FORCE_INLINE_ RID multimesh_get_2d_uniform_set(RID p_multimesh, RID p_shader, uint32_t p_set) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); + MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh); if (!multimesh->uniform_set_2d.is_valid()) { Vector<RD::Uniform> uniforms; RD::Uniform u; @@ -1776,11 +1798,11 @@ public: Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const; _FORCE_INLINE_ bool skeleton_is_valid(RID p_skeleton) { - return skeleton_owner.getornull(p_skeleton) != nullptr; + return skeleton_owner.get_or_null(p_skeleton) != nullptr; } _FORCE_INLINE_ RID skeleton_get_3d_uniform_set(RID p_skeleton, RID p_shader, uint32_t p_set) const { - Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton); ERR_FAIL_COND_V(!skeleton, RID()); ERR_FAIL_COND_V(skeleton->size == 0, RID()); if (skeleton->use_2d) { @@ -1834,7 +1856,7 @@ public: RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); _FORCE_INLINE_ RS::LightType light_get_type(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL); return light->type; @@ -1842,70 +1864,70 @@ public: AABB light_get_aabb(RID p_light) const; _FORCE_INLINE_ float light_get_param(RID p_light, RS::LightParam p_param) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, 0); return light->param[p_param]; } _FORCE_INLINE_ RID light_get_projector(RID p_light) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RID()); return light->projector; } _FORCE_INLINE_ Color light_get_color(RID p_light) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, Color()); return light->color; } _FORCE_INLINE_ Color light_get_shadow_color(RID p_light) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, Color()); return light->shadow_color; } _FORCE_INLINE_ uint32_t light_get_cull_mask(RID p_light) { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, 0); return light->cull_mask; } _FORCE_INLINE_ bool light_has_shadow(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL); return light->shadow; } _FORCE_INLINE_ bool light_has_projector(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL); return texture_owner.owns(light->projector); } _FORCE_INLINE_ bool light_is_negative(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL); return light->negative; } _FORCE_INLINE_ float light_get_transmittance_bias(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, 0.0); return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS]; } _FORCE_INLINE_ float light_get_shadow_volumetric_fog_fade(RID p_light) const { - const Light *light = light_owner.getornull(p_light); + const Light *light = light_owner.get_or_null(p_light); ERR_FAIL_COND_V(!light, 0.0); return light->param[RS::LIGHT_PARAM_SHADOW_VOLUMETRIC_FOG_FADE]; @@ -1972,62 +1994,62 @@ public: virtual void decal_set_normal_fade(RID p_decal, float p_fade); _FORCE_INLINE_ Vector3 decal_get_extents(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->extents; } _FORCE_INLINE_ RID decal_get_texture(RID p_decal, RS::DecalTexture p_texture) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->textures[p_texture]; } _FORCE_INLINE_ Color decal_get_modulate(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->modulate; } _FORCE_INLINE_ float decal_get_emission_energy(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->emission_energy; } _FORCE_INLINE_ float decal_get_albedo_mix(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->albedo_mix; } _FORCE_INLINE_ uint32_t decal_get_cull_mask(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->cull_mask; } _FORCE_INLINE_ float decal_get_upper_fade(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->upper_fade; } _FORCE_INLINE_ float decal_get_lower_fade(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->lower_fade; } _FORCE_INLINE_ float decal_get_normal_fade(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->normal_fade; } _FORCE_INLINE_ bool decal_is_distance_fade_enabled(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->distance_fade; } _FORCE_INLINE_ float decal_get_distance_fade_begin(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->distance_fade_begin; } _FORCE_INLINE_ float decal_get_distance_fade_length(RID p_decal) { - const Decal *decal = decal_owner.getornull(p_decal); + const Decal *decal = decal_owner.get_or_null(p_decal); return decal->distance_fade_length; } @@ -2102,18 +2124,18 @@ public: return lightmap_probe_capture_update_speed; } _FORCE_INLINE_ RID lightmap_get_texture(RID p_lightmap) const { - const Lightmap *lm = lightmap_owner.getornull(p_lightmap); + const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); ERR_FAIL_COND_V(!lm, RID()); return lm->light_texture; } _FORCE_INLINE_ int32_t lightmap_get_array_index(RID p_lightmap) const { ERR_FAIL_COND_V(!using_lightmap_array, -1); //only for arrays - const Lightmap *lm = lightmap_owner.getornull(p_lightmap); + const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); return lm->array_index; } _FORCE_INLINE_ bool lightmap_uses_spherical_harmonics(RID p_lightmap) const { ERR_FAIL_COND_V(!using_lightmap_array, false); //only for arrays - const Lightmap *lm = lightmap_owner.getornull(p_lightmap); + const Lightmap *lm = lightmap_owner.get_or_null(p_lightmap); return lm->uses_spherical_harmonics; } _FORCE_INLINE_ uint64_t lightmap_array_get_version() const { @@ -2182,13 +2204,13 @@ public: virtual bool particles_is_inactive(RID p_particles) const; _FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D); return particles->mode; } _FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles, uint32_t &r_trail_divisor) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, 0); if (particles->trails_enabled && particles->trail_bind_poses.size() > 1) { @@ -2201,21 +2223,21 @@ public: } _FORCE_INLINE_ bool particles_has_collision(RID p_particles) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, 0); return particles->has_collision_cache; } _FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, false); return particles->use_local_coords; } _FORCE_INLINE_ RID particles_get_instance_buffer_uniform_set(RID p_particles, RID p_shader, uint32_t p_set) { - Particles *particles = particles_owner.getornull(p_particles); + Particles *particles = particles_owner.get_or_null(p_particles); ERR_FAIL_COND_V(!particles, RID()); if (particles->particles_transforms_buffer_uniform_set.is_null()) { _particles_update_buffers(particles); @@ -2260,6 +2282,21 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const; RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const; + /* FOG VOLUMES */ + + virtual RID fog_volume_allocate(); + virtual void fog_volume_initialize(RID p_rid); + + virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape); + virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents); + virtual void fog_volume_set_material(RID p_fog_volume, RID p_material); + virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const; + virtual RID fog_volume_get_material(RID p_fog_volume) const; + virtual AABB fog_volume_get_aabb(RID p_fog_volume) const; + virtual Vector3 fog_volume_get_extents(RID p_fog_volume) const; + + /* VISIBILITY NOTIFIER */ + virtual RID visibility_notifier_allocate(); virtual void visibility_notifier_initialize(RID p_notifier); virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb); diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.cpp b/servers/rendering/renderer_rd/shader_compiler_rd.cpp index b95d4b642c..f7c8ca1487 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.cpp +++ b/servers/rendering/renderer_rd/shader_compiler_rd.cpp @@ -91,7 +91,7 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_VEC4: return 16; case SL::TYPE_MAT2: - return 32; //4 * 4 + 4 * 4 + return 32; // 4 * 4 + 4 * 4 case SL::TYPE_MAT3: return 48; // 4 * 4 + 4 * 4 + 4 * 4 case SL::TYPE_MAT4: @@ -227,6 +227,13 @@ static String _prestr(SL::DataPrecision p_pres, bool p_force_highp = false) { return ""; } +static String _constr(bool p_is_const) { + if (p_is_const) { + return "const "; + } + return ""; +} + static String _qualstr(SL::ArgumentQualifier p_qual) { switch (p_qual) { case SL::ARGUMENT_QUALIFIER_IN: @@ -417,9 +424,7 @@ void ShaderCompilerRD::_dump_function_deps(const SL::ShaderNode *p_node, const S if (i > 0) { header += ", "; } - if (fnode->arguments[i].is_const) { - header += "const "; - } + header += _constr(fnode->arguments[i].is_const); if (fnode->arguments[i].type == SL::TYPE_STRUCT) { header += _qualstr(fnode->arguments[i].qualifier) + _mkid(fnode->arguments[i].type_str) + " " + _mkid(fnode->arguments[i].name); } else { @@ -566,11 +571,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge int max_texture_uniforms = 0; int max_uniforms = 0; - for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) { - if (SL::is_sampler_type(E->get().type)) { + for (const KeyValue<StringName, SL::ShaderNode::Uniform> &E : pnode->uniforms) { + if (SL::is_sampler_type(E.value.type)) { max_texture_uniforms++; } else { - if (E->get().scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) { + if (E.value.scope == SL::ShaderNode::Uniform::SCOPE_INSTANCE) { continue; // Instances are indexed directly, don't need index uniforms. } @@ -590,8 +595,8 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge Vector<StringName> uniform_names; - for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = pnode->uniforms.front(); E; E = E->next()) { - uniform_names.push_back(E->key()); + for (const KeyValue<StringName, SL::ShaderNode::Uniform> &E : pnode->uniforms) { + uniform_names.push_back(E.key); } uniform_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced @@ -608,7 +613,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge continue; // Instances are indexed directly, don't need index uniforms. } if (SL::is_sampler_type(uniform.type)) { - ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_order) + ") uniform "; + ucode = "layout(set = " + itos(actions.texture_layout_set) + ", binding = " + itos(actions.base_texture_binding_index + uniform.texture_binding) + ") uniform "; } bool is_buffer_global = !SL::is_sampler_type(uniform.type) && uniform.scope == SL::ShaderNode::Uniform::SCOPE_GLOBAL; @@ -622,6 +627,11 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge } ucode += " " + _mkid(uniform_name); + if (uniform.array_size > 0) { + ucode += "["; + ucode += itos(uniform.array_size); + ucode += "]"; + } ucode += ";\n"; if (SL::is_sampler_type(uniform.type)) { for (int j = 0; j < STAGE_MAX; j++) { @@ -635,6 +645,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge texture.filter = uniform.filter; texture.repeat = uniform.repeat; texture.global = uniform.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL; + texture.array_size = uniform.array_size; if (texture.global) { r_gen_code.uses_global_textures = true; } @@ -650,7 +661,16 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge uniform_sizes.write[uniform.order] = _get_datatype_size(ShaderLanguage::TYPE_UINT); uniform_alignments.write[uniform.order] = _get_datatype_alignment(ShaderLanguage::TYPE_UINT); } else { - uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type); + if (uniform.array_size > 0) { + int size = _get_datatype_size(uniform.type) * uniform.array_size; + int m = (16 * uniform.array_size); + if ((size % m) != 0) { + size += m - (size % m); + } + uniform_sizes.write[uniform.order] = size; + } else { + uniform_sizes.write[uniform.order] = _get_datatype_size(uniform.type); + } uniform_alignments.write[uniform.order] = _get_datatype_alignment(uniform.type); } } @@ -724,8 +744,8 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge Vector<StringName> varying_names; - for (Map<StringName, SL::ShaderNode::Varying>::Element *E = pnode->varyings.front(); E; E = E->next()) { - varying_names.push_back(E->key()); + for (const KeyValue<StringName, SL::ShaderNode::Varying> &E : pnode->varyings) { + varying_names.push_back(E.key); } varying_names.sort_custom<StringName::AlphCompare>(); //ensure order is deterministic so the same shader is always produced @@ -776,7 +796,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge for (int i = 0; i < pnode->vconstants.size(); i++) { const SL::ShaderNode::Constant &cnode = pnode->vconstants[i]; String gcode; - gcode += "const "; + gcode += _constr(true); gcode += _prestr(cnode.precision, ShaderLanguage::is_float_type(cnode.type)); if (cnode.type == SL::TYPE_STRUCT) { gcode += _mkid(cnode.type_str); @@ -860,9 +880,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node; String declaration; - if (vdnode->is_const) { - declaration += "const "; - } + declaration += _constr(vdnode->is_const); if (vdnode->datatype == SL::TYPE_STRUCT) { declaration += _mkid(vdnode->struct_name); } else { @@ -982,9 +1000,7 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge case SL::Node::TYPE_ARRAY_DECLARATION: { SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node; String declaration; - if (adnode->is_const) { - declaration += "const "; - } + declaration += _constr(adnode->is_const); if (adnode->datatype == SL::TYPE_STRUCT) { declaration += _mkid(adnode->struct_name); } else { @@ -1074,10 +1090,32 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge if (p_default_actions.renames.has(anode->name)) { code = p_default_actions.renames[anode->name]; } else { - if (use_fragment_varying) { - code = "frag_to_light."; + if (shader->uniforms.has(anode->name)) { + //its a uniform! + const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[anode->name]; + if (u.texture_order >= 0) { + code = _mkid(anode->name); //texture, use as is + } else { + //a scalar or vector + if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) { + code = actions.base_uniform_string + _mkid(anode->name); //texture, use as is + //global variable, this means the code points to an index to the global table + code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type); + } else if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_INSTANCE) { + //instance variable, index it as such + code = "(" + p_default_actions.instance_uniform_index_variable + "+" + itos(u.instance_index) + ")"; + code = _get_global_variable_from_type_and_index(p_default_actions.global_buffer_array_variable, code, u.type); + } else { + //regular uniform, index from UBO + code = actions.base_uniform_string + _mkid(anode->name); + } + } + } else { + if (use_fragment_varying) { + code = "frag_to_light."; + } + code += _mkid(anode->name); } - code += _mkid(anode->name); } if (anode->call_expression != nullptr) { @@ -1193,46 +1231,65 @@ String ShaderCompilerRD::_dump_node_code(const SL::Node *p_node, int p_level, Ge code += ", "; } String node_code = _dump_node_code(onode->arguments[i], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - if (is_texture_func && i == 1 && onode->arguments[i]->type == SL::Node::TYPE_VARIABLE) { + if (is_texture_func && i == 1) { //need to map from texture to sampler in order to sample - const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]); + StringName texture_uniform; + bool correct_texture_uniform = false; + + switch (onode->arguments[i]->type) { + case SL::Node::TYPE_VARIABLE: { + const SL::VariableNode *varnode = static_cast<const SL::VariableNode *>(onode->arguments[i]); + texture_uniform = varnode->name; + correct_texture_uniform = true; + } break; + case SL::Node::TYPE_ARRAY: { + const SL::ArrayNode *anode = static_cast<const SL::ArrayNode *>(onode->arguments[i]); + texture_uniform = anode->name; + correct_texture_uniform = true; + } break; + default: + break; + } - StringName texture_uniform = varnode->name; - is_screen_texture = (texture_uniform == "SCREEN_TEXTURE"); + if (correct_texture_uniform) { + is_screen_texture = (texture_uniform == "SCREEN_TEXTURE"); - String sampler_name; + String sampler_name; - if (actions.custom_samplers.has(texture_uniform)) { - sampler_name = actions.custom_samplers[texture_uniform]; - } else { - if (shader->uniforms.has(texture_uniform)) { - sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat); + if (actions.custom_samplers.has(texture_uniform)) { + sampler_name = actions.custom_samplers[texture_uniform]; } else { - bool found = false; - - for (int j = 0; j < function->arguments.size(); j++) { - if (function->arguments[j].name == texture_uniform) { - if (function->arguments[j].tex_builtin_check) { - ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin)); - sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin]; - found = true; - break; - } - if (function->arguments[j].tex_argument_check) { - sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat); - found = true; - break; + if (shader->uniforms.has(texture_uniform)) { + sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat); + } else { + bool found = false; + + for (int j = 0; j < function->arguments.size(); j++) { + if (function->arguments[j].name == texture_uniform) { + if (function->arguments[j].tex_builtin_check) { + ERR_CONTINUE(!actions.custom_samplers.has(function->arguments[j].tex_builtin)); + sampler_name = actions.custom_samplers[function->arguments[j].tex_builtin]; + found = true; + break; + } + if (function->arguments[j].tex_argument_check) { + sampler_name = _get_sampler_name(function->arguments[j].tex_argument_filter, function->arguments[j].tex_argument_repeat); + found = true; + break; + } } } - } - if (!found) { - //function was most likely unused, so use anything (compiler will remove it anyway) - sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT); + if (!found) { + //function was most likely unused, so use anything (compiler will remove it anyway) + sampler_name = _get_sampler_name(ShaderLanguage::FILTER_DEFAULT, ShaderLanguage::REPEAT_DEFAULT); + } } } - } - code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")"; + code += ShaderLanguage::get_datatype_name(onode->arguments[i]->get_datatype()) + "(" + node_code + ", " + sampler_name + ")"; + } else { + code += node_code; + } } else { code += node_code; } @@ -1365,7 +1422,7 @@ Error ShaderCompilerRD::compile(RS::ShaderMode p_mode, const String &p_code, Ide } } - _err_print_error(nullptr, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER); + _err_print_error(nullptr, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), false, ERR_HANDLER_SHADER); return err; } @@ -1407,6 +1464,7 @@ void ShaderCompilerRD::initialize(DefaultIdentifierActions p_actions) { texture_functions.insert("textureLod"); texture_functions.insert("textureProjLod"); texture_functions.insert("textureGrad"); + texture_functions.insert("textureGather"); texture_functions.insert("textureSize"); texture_functions.insert("texelFetch"); } diff --git a/servers/rendering/renderer_rd/shader_compiler_rd.h b/servers/rendering/renderer_rd/shader_compiler_rd.h index 0fe9047967..2ab689c27c 100644 --- a/servers/rendering/renderer_rd/shader_compiler_rd.h +++ b/servers/rendering/renderer_rd/shader_compiler_rd.h @@ -65,6 +65,7 @@ public: ShaderLanguage::TextureFilter filter; ShaderLanguage::TextureRepeat repeat; bool global; + int array_size; }; Vector<Texture> texture_uniforms; diff --git a/servers/rendering/renderer_rd/shader_rd.cpp b/servers/rendering/renderer_rd/shader_rd.cpp index 82efa1318c..2568090918 100644 --- a/servers/rendering/renderer_rd/shader_rd.cpp +++ b/servers/rendering/renderer_rd/shader_rd.cpp @@ -174,9 +174,12 @@ void ShaderRD::_build_variant_code(StringBuilder &builder, uint32_t p_variant, c if (p_version->uniforms.size()) { builder.append("#define MATERIAL_UNIFORMS_USED\n"); } - for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) { - builder.append(String("#define ") + String(E->key()) + "_CODE_USED\n"); + for (const KeyValue<StringName, CharString> &E : p_version->code_sections) { + builder.append(String("#define ") + String(E.key) + "_CODE_USED\n"); } +#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) + builder.append("#define MOLTENVK_USED\n"); +#endif } break; case StageTemplate::Chunk::TYPE_MATERIAL_UNIFORMS: { builder.append(p_version->uniforms.get_data()); //uniforms (same for vertex and fragment) @@ -292,7 +295,7 @@ void ShaderRD::_compile_variant(uint32_t p_variant, Version *p_version) { } RS::ShaderNativeSourceCode ShaderRD::version_get_native_source_code(RID p_version) { - Version *version = version_owner.getornull(p_version); + Version *version = version_owner.get_or_null(p_version); RS::ShaderNativeSourceCode source_code; ERR_FAIL_COND_V(!version, source_code); @@ -355,8 +358,8 @@ String ShaderRD::_version_get_sha1(Version *p_version) const { hash_build.append(p_version->compute_globals.get_data()); Vector<StringName> code_sections; - for (Map<StringName, CharString>::Element *E = p_version->code_sections.front(); E; E = E->next()) { - code_sections.push_back(E->key()); + for (const KeyValue<StringName, CharString> &E : p_version->code_sections) { + code_sections.push_back(E.key); } code_sections.sort_custom<StringName::AlphCompare>(); @@ -524,14 +527,14 @@ void ShaderRD::_compile_version(Version *p_version) { void ShaderRD::version_set_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines) { ERR_FAIL_COND(is_compute); - Version *version = version_owner.getornull(p_version); + Version *version = version_owner.get_or_null(p_version); ERR_FAIL_COND(!version); version->vertex_globals = p_vertex_globals.utf8(); version->fragment_globals = p_fragment_globals.utf8(); version->uniforms = p_uniforms.utf8(); version->code_sections.clear(); - for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) { - version->code_sections[StringName(E->key().to_upper())] = E->get().utf8(); + for (const KeyValue<String, String> &E : p_code) { + version->code_sections[StringName(E.key.to_upper())] = E.value.utf8(); } version->custom_defines.clear(); @@ -549,15 +552,15 @@ void ShaderRD::version_set_code(RID p_version, const Map<String, String> &p_code void ShaderRD::version_set_compute_code(RID p_version, const Map<String, String> &p_code, const String &p_uniforms, const String &p_compute_globals, const Vector<String> &p_custom_defines) { ERR_FAIL_COND(!is_compute); - Version *version = version_owner.getornull(p_version); + Version *version = version_owner.get_or_null(p_version); ERR_FAIL_COND(!version); version->compute_globals = p_compute_globals.utf8(); version->uniforms = p_uniforms.utf8(); version->code_sections.clear(); - for (Map<String, String>::Element *E = p_code.front(); E; E = E->next()) { - version->code_sections[StringName(E->key().to_upper())] = E->get().utf8(); + for (const KeyValue<String, String> &E : p_code) { + version->code_sections[StringName(E.key.to_upper())] = E.value.utf8(); } version->custom_defines.clear(); @@ -573,7 +576,7 @@ void ShaderRD::version_set_compute_code(RID p_version, const Map<String, String> } bool ShaderRD::version_is_valid(RID p_version) { - Version *version = version_owner.getornull(p_version); + Version *version = version_owner.get_or_null(p_version); ERR_FAIL_COND_V(!version, false); if (version->dirty) { @@ -585,7 +588,7 @@ bool ShaderRD::version_is_valid(RID p_version) { bool ShaderRD::version_free(RID p_version) { if (version_owner.owns(p_version)) { - Version *version = version_owner.getornull(p_version); + Version *version = version_owner.get_or_null(p_version); _clear_version(version); version_owner.free(p_version); } else { diff --git a/servers/rendering/renderer_rd/shader_rd.h b/servers/rendering/renderer_rd/shader_rd.h index 529328f0ed..984b168659 100644 --- a/servers/rendering/renderer_rd/shader_rd.h +++ b/servers/rendering/renderer_rd/shader_rd.h @@ -141,7 +141,7 @@ public: ERR_FAIL_INDEX_V(p_variant, variant_defines.size(), RID()); ERR_FAIL_COND_V(!variants_enabled[p_variant], RID()); - Version *version = version_owner.getornull(p_version); + Version *version = version_owner.get_or_null(p_version); ERR_FAIL_COND_V(!version, RID()); if (version->dirty) { diff --git a/servers/rendering/renderer_rd/shaders/blit.glsl b/servers/rendering/renderer_rd/shaders/blit.glsl index 967da1e6e4..8051f96738 100644 --- a/servers/rendering/renderer_rd/shaders/blit.glsl +++ b/servers/rendering/renderer_rd/shaders/blit.glsl @@ -5,6 +5,7 @@ #VERSION_DEFINES layout(push_constant, binding = 0, std140) uniform Pos { + vec4 src_rect; vec4 dst_rect; vec2 eye_center; @@ -22,8 +23,8 @@ layout(location = 0) out vec2 uv; void main() { vec2 base_arr[4] = vec2[](vec2(0.0, 0.0), vec2(0.0, 1.0), vec2(1.0, 1.0), vec2(1.0, 0.0)); - uv = base_arr[gl_VertexIndex]; - vec2 vtx = data.dst_rect.xy + uv * data.dst_rect.zw; + uv = data.src_rect.xy + base_arr[gl_VertexIndex] * data.src_rect.zw; + vec2 vtx = data.dst_rect.xy + base_arr[gl_VertexIndex] * data.dst_rect.zw; gl_Position = vec4(vtx * 2.0 - 1.0, 0.0, 1.0); } @@ -34,6 +35,7 @@ void main() { #VERSION_DEFINES layout(push_constant, binding = 0, std140) uniform Pos { + vec4 src_rect; vec4 dst_rect; vec2 eye_center; diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl index 2911e8b731..65a621b203 100644 --- a/servers/rendering/renderer_rd/shaders/canvas.glsl +++ b/servers/rendering/renderer_rd/shaders/canvas.glsl @@ -91,7 +91,6 @@ void main() { uint instancing = draw_data.flags & FLAGS_INSTANCING_MASK; #ifdef USE_ATTRIBUTES - if (instancing > 1) { // trails @@ -128,37 +127,37 @@ void main() { vertex = new_vertex; color *= pcolor; - } else #endif // USE_ATTRIBUTES + { + if (instancing == 1) { + uint stride = 2; + { + if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) { + stride += 1; + } + if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { + stride += 1; + } + } + + uint offset = stride * gl_InstanceIndex; + + mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); + offset += 2; - if (instancing == 1) { - uint stride = 2; - { if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) { - stride += 1; + color *= transforms.data[offset]; + offset += 1; } + if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { - stride += 1; + instance_custom = transforms.data[offset]; } - } - - uint offset = stride * gl_InstanceIndex; - mat4 matrix = mat4(transforms.data[offset + 0], transforms.data[offset + 1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0)); - offset += 2; - - if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_COLORS)) { - color *= transforms.data[offset]; - offset += 1; - } - - if (bool(draw_data.flags & FLAGS_INSTANCING_HAS_CUSTOM_DATA)) { - instance_custom = transforms.data[offset]; + matrix = transpose(matrix); + world_matrix = world_matrix * matrix; } - - matrix = transpose(matrix); - world_matrix = world_matrix * matrix; } #if !defined(USE_ATTRIBUTES) && !defined(USE_PRIMITIVE) diff --git a/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl new file mode 100644 index 0000000000..4e2ba84033 --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/fsr_upscale.glsl @@ -0,0 +1,173 @@ +/*************************************************************************/ +/* fsr_upscale.glsl */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#[compute] + +#version 450 + +#VERSION_DEFINES + +#define A_GPU +#define A_GLSL + +#ifdef MODE_FSR_UPSCALE_NORMAL + +#define A_HALF + +#endif + +#include "thirdparty/amd-fsr/ffx_a.h" + +layout(local_size_x = 64, local_size_y = 1, local_size_z = 1) in; + +layout(rgba16f, set = 1, binding = 0) uniform restrict writeonly image2D fsr_image; +layout(set = 0, binding = 0) uniform sampler2D source_image; + +#define FSR_UPSCALE_PASS_TYPE_EASU 0 +#define FSR_UPSCALE_PASS_TYPE_RCAS 1 + +layout(push_constant, binding = 1, std430) uniform Params { + float resolution_width; + float resolution_height; + float upscaled_width; + float upscaled_height; + float sharpness; + int pass; +} +params; + +AU4 Const0, Const1, Const2, Const3; + +#ifdef MODE_FSR_UPSCALE_FALLBACK + +#define FSR_EASU_F +AF4 FsrEasuRF(AF2 p) { + AF4 res = textureGather(source_image, p, 0); + return res; +} +AF4 FsrEasuGF(AF2 p) { + AF4 res = textureGather(source_image, p, 1); + return res; +} +AF4 FsrEasuBF(AF2 p) { + AF4 res = textureGather(source_image, p, 2); + return res; +} + +#define FSR_RCAS_F +AF4 FsrRcasLoadF(ASU2 p) { + return AF4(texelFetch(source_image, ASU2(p), 0)); +} +void FsrRcasInputF(inout AF1 r, inout AF1 g, inout AF1 b) {} + +#else + +#define FSR_EASU_H +AH4 FsrEasuRH(AF2 p) { + AH4 res = AH4(textureGather(source_image, p, 0)); + return res; +} +AH4 FsrEasuGH(AF2 p) { + AH4 res = AH4(textureGather(source_image, p, 1)); + return res; +} +AH4 FsrEasuBH(AF2 p) { + AH4 res = AH4(textureGather(source_image, p, 2)); + return res; +} + +#define FSR_RCAS_H +AH4 FsrRcasLoadH(ASW2 p) { + return AH4(texelFetch(source_image, ASU2(p), 0)); +} +void FsrRcasInputH(inout AH1 r, inout AH1 g, inout AH1 b) {} + +#endif + +#include "thirdparty/amd-fsr/ffx_fsr1.h" + +void fsr_easu_pass(AU2 pos) { +#ifdef MODE_FSR_UPSCALE_NORMAL + + AH3 Gamma2Color = AH3(0, 0, 0); + FsrEasuH(Gamma2Color, pos, Const0, Const1, Const2, Const3); + imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1)); + +#else + + AF3 Gamma2Color = AF3(0, 0, 0); + FsrEasuF(Gamma2Color, pos, Const0, Const1, Const2, Const3); + imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1)); + +#endif +} + +void fsr_rcas_pass(AU2 pos) { +#ifdef MODE_FSR_UPSCALE_NORMAL + + AH3 Gamma2Color = AH3(0, 0, 0); + FsrRcasH(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0); + imageStore(fsr_image, ASU2(pos), AH4(Gamma2Color, 1)); + +#else + + AF3 Gamma2Color = AF3(0, 0, 0); + FsrRcasF(Gamma2Color.r, Gamma2Color.g, Gamma2Color.b, pos, Const0); + imageStore(fsr_image, ASU2(pos), AF4(Gamma2Color, 1)); + +#endif +} + +void fsr_pass(AU2 pos) { + if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) { + fsr_easu_pass(pos); + } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) { + fsr_rcas_pass(pos); + } +} + +void main() { + // Clang does not like unused functions. If ffx_a.h is included in the binary, clang will throw a fit and not compile so we must configure FSR in this shader + if (params.pass == FSR_UPSCALE_PASS_TYPE_EASU) { + FsrEasuCon(Const0, Const1, Const2, Const3, params.resolution_width, params.resolution_height, params.resolution_width, params.resolution_height, params.upscaled_width, params.upscaled_height); + } else if (params.pass == FSR_UPSCALE_PASS_TYPE_RCAS) { + FsrRcasCon(Const0, params.sharpness); + } + + AU2 gxy = ARmp8x8(gl_LocalInvocationID.x) + AU2(gl_WorkGroupID.x << 4u, gl_WorkGroupID.y << 4u); + + fsr_pass(gxy); + gxy.x += 8u; + fsr_pass(gxy); + gxy.y += 8u; + fsr_pass(gxy); + gxy.x -= 8u; + fsr_pass(gxy); +} diff --git a/servers/rendering/renderer_rd/shaders/gi.glsl b/servers/rendering/renderer_rd/shaders/gi.glsl index 60c881881d..5528ea3659 100644 --- a/servers/rendering/renderer_rd/shaders/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/gi.glsl @@ -97,12 +97,10 @@ layout(push_constant, binding = 0, std430) uniform Params { vec4 proj_info; - vec3 ao_color; uint max_voxel_gi_instances; - bool high_quality_vct; bool orthogonal; - uint pad[2]; + uint pad; mat3x4 cam_rotation; } diff --git a/servers/rendering/renderer_rd/shaders/particles.glsl b/servers/rendering/renderer_rd/shaders/particles.glsl index 9f8410fd8a..328becbc20 100644 --- a/servers/rendering/renderer_rd/shaders/particles.glsl +++ b/servers/rendering/renderer_rd/shaders/particles.glsl @@ -567,11 +567,11 @@ void main() { depth = particle_size - s; const float EPSILON = 0.001; normal = mat3(FRAME.colliders[i].transform) * - normalize( - vec3( - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r, - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r, - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r)); + normalize( + vec3( + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(EPSILON, 0.0, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(EPSILON, 0.0, 0.0)).r, + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, EPSILON, 0.0)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, EPSILON, 0.0)).r, + texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos + vec3(0.0, 0.0, EPSILON)).r - texture(sampler3D(sdf_vec_textures[FRAME.colliders[i].texture_index], material_samplers[SAMPLER_LINEAR_CLAMP]), uvw_pos - vec3(0.0, 0.0, EPSILON)).r)); } } break; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl index 99714b4504..97c913d489 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_aa_inc.glsl @@ -2,7 +2,7 @@ float hash_2d(vec2 p) { return fract(1.0e4 * sin(17.0 * p.x + 0.1 * p.y) * - (0.1 + abs(sin(13.0 * p.y + p.x)))); + (0.1 + abs(sin(13.0 * p.y + p.x)))); } float hash_3d(vec3 p) { @@ -29,8 +29,7 @@ float compute_alpha_hash_threshold(vec3 pos, float hash_scale) { vec3 cases = vec3(a_interp * a_interp / (2.0 * min_lerp * (1.0 - min_lerp)), (a_interp - 0.5 * min_lerp) / (1.0 - min_lerp), - 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / - (2.0 * min_lerp * (1.0 - min_lerp)))); + 1.0 - ((1.0 - a_interp) * (1.0 - a_interp) / (2.0 * min_lerp * (1.0 - min_lerp)))); float alpha_hash_threshold = (lerp_factor < (1.0 - min_lerp)) ? ((lerp_factor < min_lerp) ? cases.x : cases.y) : cases.z; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl index edbe1031b7..e4628b2d5a 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered.glsl @@ -6,6 +6,8 @@ #include "scene_forward_clustered_inc.glsl" +#define SHADER_IS_SRGB false + /* INPUT ATTRIBS */ layout(location = 0) in vec3 vertex_attrib; @@ -95,7 +97,7 @@ layout(location = 8) out float dp_clip; #endif -layout(location = 9) out flat uint instance_index; +layout(location = 9) out flat uint instance_index_interp; invariant gl_Position; @@ -107,13 +109,15 @@ void main() { color_interp = color_attrib; #endif - instance_index = draw_call.instance_index; + uint instance_index = draw_call.instance_index; bool is_multimesh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_MULTIMESH); if (!is_multimesh) { instance_index += gl_InstanceIndex; } + instance_index_interp = instance_index; + mat4 world_matrix = instances.data[instance_index].transform; mat3 world_normal_matrix; @@ -356,6 +360,8 @@ void main() { #VERSION_DEFINES +#define SHADER_IS_SRGB false + /* Specialization Constants (Toggles) */ layout(constant_id = 0) const bool sc_use_forward_gi = false; @@ -410,7 +416,7 @@ layout(location = 8) in float dp_clip; #endif -layout(location = 9) in flat uint instance_index; +layout(location = 9) in flat uint instance_index_interp; //defines to keep compatibility with vertex @@ -524,14 +530,14 @@ vec4 fog_process(vec3 vertex) { } } - float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density)); + float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density)); - if (abs(scene_data.fog_height_density) > 0.001) { + if (abs(scene_data.fog_height_density) >= 0.0001) { float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y; - float y_dist = scene_data.fog_height - y; + float y_dist = y - scene_data.fog_height; - float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0); + float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density)); fog_amount = max(vfog_amount, fog_amount); } @@ -564,6 +570,8 @@ void main() { discard; #endif + uint instance_index = instance_index_interp; + //lay out everything, whathever is unused is optimized away anyway vec3 vertex = vertex_interp; vec3 view = -normalize(vertex_interp); @@ -593,7 +601,7 @@ void main() { float ao = 1.0; float ao_light_affect = 0.0; - float alpha = 1.0; + float alpha = float(instances.data[instance_index].flags >> INSTANCE_FLAGS_FADE_SHIFT) / float(255.0); #if defined(TANGENT_USED) || defined(NORMAL_MAP_USED) || defined(LIGHT_ANISOTROPY_USED) vec3 binormal = normalize(binormal_interp); @@ -687,7 +695,7 @@ void main() { #endif // ALPHA_ANTIALIASING_EDGE_USED #ifdef USE_OPAQUE_PREPASS - if (alpha < opaque_prepass_threshold) { + if (alpha < scene_data.opaque_prepass_threshold) { discard; } #endif // USE_OPAQUE_PREPASS @@ -903,6 +911,7 @@ void main() { if (scene_data.use_reflection_cubemap) { vec3 ref_vec = reflect(-view, normal); + float horizon = min(1.0 + dot(ref_vec, normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; #ifdef USE_RADIANCE_CUBEMAP_ARRAY @@ -915,7 +924,6 @@ void main() { specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY - float horizon = min(1.0 + dot(ref_vec, normal), 1.0); specular_light *= horizon * horizon; specular_light *= scene_data.ambient_light_color_energy.a; } @@ -964,15 +972,15 @@ void main() { const float c4 = 0.886227; const float c5 = 0.247708; ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) + - c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z + - c4 * lightmap_captures.data[index].sh[0].rgb - - c5 * lightmap_captures.data[index].sh[6].rgb + - 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y + - 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z + - 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z + - 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x + - 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + - 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); + c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z + + c4 * lightmap_captures.data[index].sh[0].rgb - + c5 * lightmap_captures.data[index].sh[6].rgb + + 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y + + 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z + + 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z + + 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x + + 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + + 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); } else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); @@ -1249,9 +1257,10 @@ void main() { // LIGHTING #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) - { //directional light + { // Directional light. - // Do shadow and lighting in two passes to reduce register pressure + // Do shadow and lighting in two passes to reduce register pressure. +#ifndef SHADOWS_DISABLED uint shadow0 = 0; uint shadow1 = 0; @@ -1270,21 +1279,21 @@ void main() { float shadow = 1.0; - //version with soft shadows, more expensive if (directional_lights.data[i].shadow_enabled) { - if (sc_use_directional_soft_shadows && directional_lights.data[i].softshadow_angle > 0) { - float depth_z = -vertex.z; - - vec3 shadow_color = vec3(0.0); - vec3 light_dir = directional_lights.data[i].direction; + float depth_z = -vertex.z; + vec3 light_dir = directional_lights.data[i].direction; + vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))); -#define BIAS_FUNC(m_var, m_idx) \ - m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ - vec3 normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))) * directional_lights.data[i].shadow_normal_bias[m_idx]; \ - normal_bias -= light_dir * dot(light_dir, normal_bias); \ +#define BIAS_FUNC(m_var, m_idx) \ + m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ + vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \ + normal_bias -= light_dir * dot(light_dir, normal_bias); \ m_var.xyz += normal_bias; - uint blend_index = 0; + //version with soft shadows, more expensive + if (sc_use_directional_soft_shadows && directional_lights.data[i].softshadow_angle > 0) { + uint blend_count = 0; + const uint blend_max = directional_lights.data[i].blend_splits ? 2 : 1; if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { vec4 v = vec4(vertex, 1.0); @@ -1299,10 +1308,10 @@ void main() { float test_radius = (range_pos - range_begin) * directional_lights.data[i].softshadow_angle; vec2 tex_scale = directional_lights.data[i].uv_scale1 * test_radius; shadow = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - blend_index++; + blend_count++; } - if (blend_index < 2 && depth_z < directional_lights.data[i].shadow_split_offsets.y) { + if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.y) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 1) @@ -1316,7 +1325,7 @@ void main() { vec2 tex_scale = directional_lights.data[i].uv_scale2 * test_radius; float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - if (blend_index == 0) { + if (blend_count == 0) { shadow = s; } else { //blend @@ -1324,10 +1333,10 @@ void main() { shadow = mix(shadow, s, blend); } - blend_index++; + blend_count++; } - if (blend_index < 2 && depth_z < directional_lights.data[i].shadow_split_offsets.z) { + if (blend_count < blend_max && depth_z < directional_lights.data[i].shadow_split_offsets.z) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 2) @@ -1341,7 +1350,7 @@ void main() { vec2 tex_scale = directional_lights.data[i].uv_scale3 * test_radius; float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - if (blend_index == 0) { + if (blend_count == 0) { shadow = s; } else { //blend @@ -1349,10 +1358,10 @@ void main() { shadow = mix(shadow, s, blend); } - blend_index++; + blend_count++; } - if (blend_index < 2) { + if (blend_count < blend_max) { vec4 v = vec4(vertex, 1.0); BIAS_FUNC(v, 3) @@ -1366,7 +1375,7 @@ void main() { vec2 tex_scale = directional_lights.data[i].uv_scale4 * test_radius; float s = sample_directional_soft_shadow(directional_shadow_atlas, pssm_coord.xyz, tex_scale * directional_lights.data[i].soft_shadow_scale); - if (blend_index == 0) { + if (blend_count == 0) { shadow = s; } else { //blend @@ -1375,21 +1384,9 @@ void main() { } } -#undef BIAS_FUNC } else { //no soft shadows - float depth_z = -vertex.z; - vec4 pssm_coord; - vec3 light_dir = directional_lights.data[i].direction; - vec3 base_normal_bias = normalize(normal_interp) * (1.0 - max(0.0, dot(light_dir, -normalize(normal_interp)))); - -#define BIAS_FUNC(m_var, m_idx) \ - m_var.xyz += light_dir * directional_lights.data[i].shadow_bias[m_idx]; \ - vec3 normal_bias = base_normal_bias * directional_lights.data[i].shadow_normal_bias[m_idx]; \ - normal_bias -= light_dir * dot(light_dir, normal_bias); \ - m_var.xyz += normal_bias; - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { vec4 v = vec4(vertex, 1.0); @@ -1448,11 +1445,11 @@ void main() { float shadow2 = sample_directional_pcf_shadow(directional_shadow_atlas, scene_data.directional_shadow_pixel_size * directional_lights.data[i].soft_shadow_scale, pssm_coord); shadow = mix(shadow, shadow2, pssm_blend); } + } - shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance + shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, vertex.z)); //done with negative values for performance #undef BIAS_FUNC - } } // shadows if (i < 4) { @@ -1461,6 +1458,7 @@ void main() { shadow1 |= uint(clamp(shadow * 255.0, 0.0, 255.0)) << ((i - 4) * 8); } } +#endif // SHADOWS_DISABLED for (uint i = 0; i < 8; i++) { if (i >= scene_data.directional_light_count) { @@ -1523,18 +1521,19 @@ void main() { #endif float shadow = 1.0; - +#ifndef SHADOWS_DISABLED if (i < 4) { shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; } else { shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; } +#endif blur_shadow(shadow); float size_A = sc_use_light_soft_shadows ? directional_lights.data[i].size : 0.0; - light_compute(normal, directional_lights.data[i].direction, normalize(view), size_A, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, + light_compute(normal, directional_lights.data[i].direction, normalize(view), size_A, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1545,7 +1544,7 @@ void main() { transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim, rim_tint, albedo, + rim, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1553,9 +1552,6 @@ void main() { #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif diffuse_light, specular_light); } @@ -1608,7 +1604,7 @@ void main() { shadow = blur_shadow(shadow); - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1620,7 +1616,6 @@ void main() { #ifdef LIGHT_RIM_USED rim, rim_tint, - albedo, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1628,9 +1623,6 @@ void main() { #ifdef LIGHT_ANISOTROPY_USED tangent, binormal, anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif diffuse_light, specular_light); } } @@ -1684,7 +1676,7 @@ void main() { shadow = blur_shadow(shadow); - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1696,7 +1688,6 @@ void main() { #ifdef LIGHT_RIM_USED rim, rim_tint, - albedo, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1704,9 +1695,6 @@ void main() { #ifdef LIGHT_ANISOTROPY_USED tangent, binormal, anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif diffuse_light, specular_light); } } @@ -1723,7 +1711,7 @@ void main() { #ifdef USE_OPAQUE_PREPASS - if (alpha < opaque_prepass_threshold) { + if (alpha < scene_data.opaque_prepass_threshold) { discard; } @@ -1769,7 +1757,11 @@ void main() { } } +#ifdef MOLTENVK_USED + imageStore(geom_facing_grid, grid_pos, uvec4(imageLoad(geom_facing_grid, grid_pos).r | facing_bits)); //store facing bits +#else imageAtomicOr(geom_facing_grid, grid_pos, facing_bits); //store facing bits +#endif if (length(emission) > 0.001) { float lumas[6]; @@ -1909,7 +1901,6 @@ void main() { // Draw "fixed" fog before volumetric fog to ensure volumetric fog can appear in front of the sky. frag_color.rgb = mix(frag_color.rgb, fog.rgb, fog.a); - ; #endif //MODE_MULTIPLE_RENDER_TARGETS diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl index b53bf6a6d4..be29cf4f58 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_clustered_inc.glsl @@ -68,6 +68,7 @@ layout(set = 0, binding = 4) uniform sampler light_projector_sampler; #define INSTANCE_FLAGS_MULTIMESH_HAS_COLOR (1 << 14) #define INSTANCE_FLAGS_MULTIMESH_HAS_CUSTOM_DATA (1 << 15) #define INSTANCE_FLAGS_PARTICLE_TRAIL_SHIFT 16 +#define INSTANCE_FLAGS_FADE_SHIFT 24 //3 bits of stride #define INSTANCE_FLAGS_PARTICLE_TRAIL_MASK 0xFF @@ -207,9 +208,8 @@ layout(set = 1, binding = 0, std140) uniform SceneData { float roughness_limiter_amount; float roughness_limiter_limit; - uvec2 roughness_limiter_pad; - - vec4 ao_color; + float opaque_prepass_threshold; + uint roughness_limiter_pad; mat4 sdf_to_bounds; diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl index f3db4abe3b..d22f936a35 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -73,7 +73,7 @@ vec3 F0(float metallic, float specular, vec3 albedo) { return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, +void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float attenuation, vec3 f0, uint orms, float specular_amount, vec3 albedo, inout float alpha, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -84,7 +84,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float transmittance_z, #endif #ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, + float rim, float rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED float clearcoat, float clearcoat_gloss, @@ -92,11 +92,13 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #ifdef LIGHT_ANISOTROPY_USED vec3 B, vec3 T, float anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif inout vec3 diffuse_light, inout vec3 specular_light) { + vec4 orms_unpacked = unpackUnorm4x8(orms); + + float roughness = orms_unpacked.y; + float metallic = orms_unpacked.z; + #if defined(LIGHT_CODE_USED) // light is written by the light shader @@ -125,9 +127,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float cLdotH = clamp(A + dot(L, H), 0.0, 1.0); #endif - float metallic = unpackUnorm4x8(orms).z; if (metallic < 1.0) { - float roughness = unpackUnorm4x8(orms).y; float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance #if defined(DIFFUSE_LAMBERT_WRAP) @@ -168,7 +168,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #if defined(LIGHT_RIM_USED) float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); - diffuse_light += rim_light * rim * mix(vec3(1.0), rim_color, rim_tint) * light_color; + diffuse_light += rim_light * rim * mix(vec3(1.0), albedo, rim_tint) * light_color; #endif #ifdef LIGHT_TRANSMITTANCE_USED @@ -179,11 +179,11 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float d = scale * abs(transmittance_z); float dd = -d * d; vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) + - vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + - vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + - vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + - vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + - vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); + vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) + + vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) + + vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) + + vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) + + vec3(0.078, 0.0, 0.0) * exp(dd / 7.41); diffuse_light += profile * transmittance_color.a * light_color * clamp(transmittance_boost - NdotL, 0.0, 1.0) * (1.0 / M_PI); #else @@ -199,7 +199,6 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #endif //LIGHT_TRANSMITTANCE_USED } - float roughness = unpackUnorm4x8(orms).y; if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely // D @@ -211,7 +210,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float blinn = pow(cNdotH, shininess); blinn *= (shininess + 2.0) * (1.0 / (8.0 * M_PI)); - specular_light += light_color * attenuation * specular_amount * blinn * f0 * unpackUnorm4x8(orms).w; + specular_light += light_color * attenuation * specular_amount * blinn * f0 * orms_unpacked.w; #elif defined(SPECULAR_PHONG) @@ -221,7 +220,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte float phong = pow(cRdotV, shininess); phong *= (shininess + 1.0) * (1.0 / (8.0 * M_PI)); - specular_light += light_color * attenuation * specular_amount * phong * f0 * unpackUnorm4x8(orms).w; + specular_light += light_color * attenuation * specular_amount * phong * f0 * orms_unpacked.w; #elif defined(SPECULAR_TOON) @@ -285,7 +284,7 @@ void light_compute(vec3 N, vec3 L, vec3 V, float A, vec3 light_color, float atte #endif //defined(LIGHT_CODE_USED) } -#ifndef USE_NO_SHADOWS +#ifndef SHADOWS_DISABLED // Interleaved Gradient Noise // https://www.iryoku.com/next-generation-post-processing-in-call-of-duty-advanced-warfare @@ -299,7 +298,7 @@ float sample_directional_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, ve float depth = coord.z; //if only one sample is taken, take it from the center - if (sc_directional_soft_shadow_samples == 1) { + if (sc_directional_soft_shadow_samples == 0) { return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); } @@ -325,7 +324,7 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord) { float depth = coord.z; //if only one sample is taken, take it from the center - if (sc_soft_shadow_samples == 1) { + if (sc_soft_shadow_samples == 0) { return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); } @@ -348,7 +347,7 @@ float sample_pcf_shadow(texture2D shadow, vec2 shadow_pixel_size, vec3 coord) { float sample_omni_pcf_shadow(texture2D shadow, float blur_scale, vec2 coord, vec4 uv_rect, vec2 flip_offset, float depth) { //if only one sample is taken, take it from the center - if (sc_soft_shadow_samples == 1) { + if (sc_soft_shadow_samples == 0) { vec2 pos = coord * 0.5 + 0.5; pos = uv_rect.xy + pos * uv_rect.zw; return textureProj(sampler2DShadow(shadow, shadow_sampler), vec4(pos, depth, 1.0)); @@ -431,7 +430,7 @@ float sample_directional_soft_shadow(texture2D shadow, vec3 pssm_coord, vec2 tex } } -#endif //USE_NO_SHADOWS +#endif // SHADOWS_DISABLED float get_omni_attenuation(float distance, float inv_range, float decay) { float nd = distance * inv_range; @@ -443,7 +442,7 @@ float get_omni_attenuation(float distance, float inv_range, float decay) { } float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { -#ifndef USE_NO_SHADOWS +#ifndef SHADOWS_DISABLED if (omni_lights.data[idx].shadow_enabled) { // there is a shadowmap vec2 texel_size = scene_data.shadow_atlas_pixel_size; @@ -575,7 +574,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { return 1.0; } -void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -585,7 +584,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v float transmittance_boost, #endif #ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, + float rim, float rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED float clearcoat, float clearcoat_gloss, @@ -593,9 +592,6 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_ANISOTROPY_USED vec3 binormal, vec3 tangent, float anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = omni_lights.data[idx].position - vertex; float light_length = length(light_rel_vec); @@ -701,7 +697,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v light_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, omni_lights.data[idx].specular_amount, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -712,7 +708,7 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim * omni_attenuation, rim_tint, rim_color, + rim * omni_attenuation, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -720,15 +716,12 @@ void light_process_omni(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif diffuse_light, specular_light); } float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { -#ifndef USE_NO_SHADOWS +#ifndef SHADOWS_DISABLED if (spot_lights.data[idx].shadow_enabled) { vec3 light_rel_vec = spot_lights.data[idx].position - vertex; float light_length = length(light_rel_vec); @@ -804,7 +797,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { return shadow; } -#endif //USE_NO_SHADOWS +#endif // SHADOWS_DISABLED return 1.0; } @@ -821,7 +814,7 @@ vec2 normal_to_panorama(vec3 n) { return panorama_coords; } -void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, +void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 vertex_ddx, vec3 vertex_ddy, vec3 f0, uint orms, float shadow, vec3 albedo, inout float alpha, #ifdef LIGHT_BACKLIGHT_USED vec3 backlight, #endif @@ -831,7 +824,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v float transmittance_boost, #endif #ifdef LIGHT_RIM_USED - float rim, float rim_tint, vec3 rim_color, + float rim, float rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED float clearcoat, float clearcoat_gloss, @@ -839,9 +832,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_ANISOTROPY_USED vec3 binormal, vec3 tangent, float anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - inout float alpha, -#endif inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = spot_lights.data[idx].position - vertex; @@ -908,7 +898,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v } light_attenuation *= shadow; - light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, + light_compute(normal, normalize(light_rel_vec), eye_vec, size_A, color, light_attenuation, f0, orms, spot_lights.data[idx].specular_amount, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -919,7 +909,7 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v transmittance_z, #endif #ifdef LIGHT_RIM_USED - rim * spot_attenuation, rim_tint, rim_color, + rim * spot_attenuation, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -927,9 +917,6 @@ void light_process_spot(uint idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 v #ifdef LIGHT_ANISOTROPY_USED binormal, tangent, anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif diffuse_light, specular_light); } diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl index 518b0a6c7f..e92fbecfd0 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile.glsl @@ -7,6 +7,8 @@ /* Include our forward mobile UBOs definitions etc. */ #include "scene_forward_mobile_inc.glsl" +#define SHADER_IS_SRGB false + /* INPUT ATTRIBS */ layout(location = 0) in vec3 vertex_attrib; @@ -370,6 +372,8 @@ void main() { #VERSION_DEFINES +#define SHADER_IS_SRGB false + /* Specialization Constants */ #if !defined(MODE_RENDER_DEPTH) @@ -550,14 +554,14 @@ vec4 fog_process(vec3 vertex) { } } - float fog_amount = 1.0 - exp(min(0.0, vertex.z * scene_data.fog_density)); + float fog_amount = 1.0 - exp(min(0.0, -length(vertex) * scene_data.fog_density)); - if (abs(scene_data.fog_height_density) > 0.001) { + if (abs(scene_data.fog_height_density) >= 0.0001) { float y = (scene_data.camera_matrix * vec4(vertex, 1.0)).y; - float y_dist = scene_data.fog_height - y; + float y_dist = y - scene_data.fog_height; - float vfog_amount = clamp(exp(y_dist * scene_data.fog_height_density), 0.0, 1.0); + float vfog_amount = 1.0 - exp(min(0.0, y_dist * scene_data.fog_height_density)); fog_amount = max(vfog_amount, fog_amount); } @@ -701,7 +705,7 @@ void main() { #endif // ALPHA_ANTIALIASING_EDGE_USED #ifdef USE_OPAQUE_PREPASS - if (alpha < opaque_prepass_threshold) { + if (alpha < scene_data.opaque_prepass_threshold) { discard; } #endif // USE_OPAQUE_PREPASS @@ -868,6 +872,7 @@ void main() { if (scene_data.use_reflection_cubemap) { vec3 ref_vec = reflect(-view, normal); + float horizon = min(1.0 + dot(ref_vec, normal), 1.0); ref_vec = scene_data.radiance_inverse_xform * ref_vec; #ifdef USE_RADIANCE_CUBEMAP_ARRAY @@ -880,7 +885,6 @@ void main() { specular_light = textureLod(samplerCube(radiance_cubemap, material_samplers[SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP]), ref_vec, roughness * MAX_ROUGHNESS_LOD).rgb; #endif //USE_RADIANCE_CUBEMAP_ARRAY - float horizon = min(1.0 + dot(ref_vec, normal), 1.0); specular_light *= horizon * horizon; specular_light *= scene_data.ambient_light_color_energy.a; } @@ -930,15 +934,15 @@ void main() { const float c4 = 0.886227; const float c5 = 0.247708; ambient_light += (c1 * lightmap_captures.data[index].sh[8].rgb * (wnormal.x * wnormal.x - wnormal.y * wnormal.y) + - c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z + - c4 * lightmap_captures.data[index].sh[0].rgb - - c5 * lightmap_captures.data[index].sh[6].rgb + - 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y + - 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z + - 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z + - 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x + - 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + - 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); + c3 * lightmap_captures.data[index].sh[6].rgb * wnormal.z * wnormal.z + + c4 * lightmap_captures.data[index].sh[0].rgb - + c5 * lightmap_captures.data[index].sh[6].rgb + + 2.0 * c1 * lightmap_captures.data[index].sh[4].rgb * wnormal.x * wnormal.y + + 2.0 * c1 * lightmap_captures.data[index].sh[7].rgb * wnormal.x * wnormal.z + + 2.0 * c1 * lightmap_captures.data[index].sh[5].rgb * wnormal.y * wnormal.z + + 2.0 * c2 * lightmap_captures.data[index].sh[3].rgb * wnormal.x + + 2.0 * c2 * lightmap_captures.data[index].sh[1].rgb * wnormal.y + + 2.0 * c2 * lightmap_captures.data[index].sh[2].rgb * wnormal.z); } else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP); @@ -1046,7 +1050,7 @@ void main() { #if !defined(MODE_RENDER_DEPTH) && !defined(MODE_UNSHADED) if (!sc_disable_directional_lights) { //directional light - +#ifndef SHADOWS_DISABLED // Do shadow and lighting in two passes to reduce register pressure uint shadow0 = 0; uint shadow1 = 0; @@ -1322,6 +1326,8 @@ void main() { } } +#endif // SHADOWS_DISABLED + for (uint i = 0; i < 8; i++) { if (i >= scene_data.directional_light_count) { break; @@ -1334,16 +1340,16 @@ void main() { // We're not doing light transmittence float shadow = 1.0; - +#ifndef SHADOWS_DISABLED if (i < 4) { shadow = float(shadow0 >> (i * 8) & 0xFF) / 255.0; } else { shadow = float(shadow1 >> ((i - 4) * 8) & 0xFF) / 255.0; } - +#endif blur_shadow(shadow); - light_compute(normal, directional_lights.data[i].direction, normalize(view), 0.0, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, + light_compute(normal, directional_lights.data[i].direction, normalize(view), 0.0, directional_lights.data[i].color * directional_lights.data[i].energy, shadow, f0, orms, 1.0, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1356,7 +1362,7 @@ void main() { #endif */ #ifdef LIGHT_RIM_USED - rim, rim_tint, albedo, + rim, rim_tint, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1367,9 +1373,6 @@ void main() { #ifdef USE_SOFT_SHADOW directional_lights.data[i].size, #endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif diffuse_light, specular_light); } @@ -1393,7 +1396,7 @@ void main() { shadow = blur_shadow(shadow); - light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, + light_process_omni(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1407,7 +1410,6 @@ void main() { #ifdef LIGHT_RIM_USED rim, rim_tint, - albedo, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1415,9 +1417,6 @@ void main() { #ifdef LIGHT_ANISOTROPY_USED tangent, binormal, anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif diffuse_light, specular_light); } } //omni lights @@ -1441,7 +1440,7 @@ void main() { shadow = blur_shadow(shadow); - light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, + light_process_spot(light_index, vertex, view, normal, vertex_ddx, vertex_ddy, f0, orms, shadow, albedo, alpha, #ifdef LIGHT_BACKLIGHT_USED backlight, #endif @@ -1455,7 +1454,6 @@ void main() { #ifdef LIGHT_RIM_USED rim, rim_tint, - albedo, #endif #ifdef LIGHT_CLEARCOAT_USED clearcoat, clearcoat_gloss, @@ -1463,9 +1461,6 @@ void main() { #ifdef LIGHT_ANISOTROPY_USED tangent, binormal, anisotropy, #endif -#ifdef USE_SHADOW_TO_OPACITY - alpha, -#endif diffuse_light, specular_light); } } //spot lights @@ -1481,7 +1476,7 @@ void main() { #ifdef USE_OPAQUE_PREPASS - if (alpha < opaque_prepass_threshold) { + if (alpha < scene_data.opaque_prepass_threshold) { discard; } diff --git a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl index dd8879acb4..a9a4fce82a 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_mobile_inc.glsl @@ -168,9 +168,8 @@ layout(set = 1, binding = 0, std140) uniform SceneData { mediump float roughness_limiter_amount; mediump float roughness_limiter_limit; - uvec2 roughness_limiter_pad; - - mediump vec4 ao_color; + mediump float opaque_prepass_threshold; + uint roughness_limiter_pad; bool fog_enabled; highp float fog_density; diff --git a/servers/rendering/renderer_rd/shaders/tonemap.glsl b/servers/rendering/renderer_rd/shaders/tonemap.glsl index 4411587116..948c6e1e39 100644 --- a/servers/rendering/renderer_rd/shaders/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/tonemap.glsl @@ -140,7 +140,7 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size; return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + - (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); + (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); } #define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) @@ -169,16 +169,33 @@ vec3 tonemap_filmic(vec3 color, float white) { return color_tonemapped / white_tonemapped; } +// Adapted from https://github.com/TheRealMJP/BakingLab/blob/master/BakingLab/ACES.hlsl +// (MIT License). vec3 tonemap_aces(vec3 color, float white) { - const float exposure_bias = 0.85f; - const float A = 2.51f * exposure_bias * exposure_bias; - const float B = 0.03f * exposure_bias; - const float C = 2.43f * exposure_bias * exposure_bias; - const float D = 0.59f * exposure_bias; - const float E = 0.14f; - - vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E); - float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E); + const float exposure_bias = 1.8f; + const float A = 0.0245786f; + const float B = 0.000090537f; + const float C = 0.983729f; + const float D = 0.432951f; + const float E = 0.238081f; + + // Exposure bias baked into transform to save shader instructions. Equivalent to `color *= exposure_bias` + const mat3 rgb_to_rrt = mat3( + vec3(0.59719f * exposure_bias, 0.35458f * exposure_bias, 0.04823f * exposure_bias), + vec3(0.07600f * exposure_bias, 0.90834f * exposure_bias, 0.01566f * exposure_bias), + vec3(0.02840f * exposure_bias, 0.13383f * exposure_bias, 0.83777f * exposure_bias)); + + const mat3 odt_to_rgb = mat3( + vec3(1.60475f, -0.53108f, -0.07367f), + vec3(-0.10208f, 1.10813f, -0.00605f), + vec3(-0.00327f, -0.07276f, 1.07602f)); + + color *= rgb_to_rrt; + vec3 color_tonemapped = (color * (color + A) - B) / (color * (C * color + D) + E); + color_tonemapped *= odt_to_rgb; + + white *= exposure_bias; + float white_tonemapped = (white * (white + A) - B) / (white * (C * white + D) + E); return color_tonemapped / white_tonemapped; } @@ -200,15 +217,16 @@ vec3 linear_to_srgb(vec3 color) { #define TONEMAPPER_ACES 3 vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color - + // Ensure color values passed to tonemappers are positive. + // They can be negative in the case of negative lights, which leads to undesired behavior. if (params.tonemapper == TONEMAPPER_LINEAR) { return color; } else if (params.tonemapper == TONEMAPPER_REINHARD) { - return tonemap_reinhard(color, white); + return tonemap_reinhard(max(vec3(0.0f), color), white); } else if (params.tonemapper == TONEMAPPER_FILMIC) { - return tonemap_filmic(color, white); + return tonemap_filmic(max(vec3(0.0f), color), white); } else { // TONEMAPPER_ACES - return tonemap_aces(color, white); + return tonemap_aces(max(vec3(0.0f), color), white); } } @@ -323,14 +341,14 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { dir.y = ((lumaNW + lumaSW) - (lumaNE + lumaSE)); float dirReduce = max((lumaNW + lumaNE + lumaSW + lumaSE) * - (0.25 * FXAA_REDUCE_MUL), + (0.25 * FXAA_REDUCE_MUL), FXAA_REDUCE_MIN); float rcpDirMin = 1.0 / (min(abs(dir.x), abs(dir.y)) + dirReduce); dir = min(vec2(FXAA_SPAN_MAX, FXAA_SPAN_MAX), max(vec2(-FXAA_SPAN_MAX, -FXAA_SPAN_MAX), dir * rcpDirMin)) * - params.pixel_size; + params.pixel_size; #ifdef MULTIVIEW vec3 rgbA = 0.5 * exposure * (textureLod(source_color, vec3(uv_interp + dir * (1.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * (2.0 / 3.0 - 0.5), ViewIndex), 0.0).xyz) * params.luminance_multiplier; @@ -401,9 +419,7 @@ void main() { color += screen_space_dither(gl_FragCoord.xy); } - // Ensure color values passed to tonemappers are positive. - // They can be negative in the case of negative lights, which leads to undesired behavior. - color = apply_tonemapping(max(vec3(0.0), color), params.white); + color = apply_tonemapping(color, params.white); color = linear_to_srgb(color); // regular linear -> SRGB conversion diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl index f2010222e5..181d3b272f 100644 --- a/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog.glsl @@ -4,219 +4,103 @@ #VERSION_DEFINES -/* Do not use subgroups here, seems there is not much advantage and causes glitches -#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) -#extension GL_KHR_shader_subgroup_ballot: enable -#extension GL_KHR_shader_subgroup_arithmetic: enable - -#define USE_SUBGROUPS -#endif -*/ - -#if defined(MODE_FOG) || defined(MODE_FILTER) - -layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; - -#endif - -#if defined(MODE_DENSITY) - layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; -#endif +#define SAMPLER_NEAREST_CLAMP 0 +#define SAMPLER_LINEAR_CLAMP 1 +#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2 +#define SAMPLER_LINEAR_WITH_MIPMAPS_CLAMP 3 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_CLAMP 4 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_CLAMP 5 +#define SAMPLER_NEAREST_REPEAT 6 +#define SAMPLER_LINEAR_REPEAT 7 +#define SAMPLER_NEAREST_WITH_MIPMAPS_REPEAT 8 +#define SAMPLER_LINEAR_WITH_MIPMAPS_REPEAT 9 +#define SAMPLER_NEAREST_WITH_MIPMAPS_ANISOTROPIC_REPEAT 10 +#define SAMPLER_LINEAR_WITH_MIPMAPS_ANISOTROPIC_REPEAT 11 + +#define DENSITY_SCALE 1024.0 #include "cluster_data_inc.glsl" #include "light_data_inc.glsl" #define M_PI 3.14159265359 -layout(set = 0, binding = 1) uniform texture2D shadow_atlas; -layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas; - -layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { - LightData data[]; -} -omni_lights; - -layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { - LightData data[]; -} -spot_lights; +layout(set = 0, binding = 1) uniform sampler material_samplers[12]; -layout(set = 0, binding = 5, std140) uniform DirectionalLights { - DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +layout(set = 0, binding = 2, std430) restrict readonly buffer GlobalVariableData { + vec4 data[]; } -directional_lights; - -layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer { - uint data[]; -} -cluster_buffer; - -layout(set = 0, binding = 7) uniform sampler linear_sampler; - -#ifdef MODE_DENSITY -layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map; -layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused -#endif - -#ifdef MODE_FOG -layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map; -layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map; -#endif - -#ifdef MODE_FILTER -layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map; -layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map; -#endif - -layout(set = 0, binding = 10) uniform sampler shadow_sampler; - -#define MAX_VOXEL_GI_INSTANCES 8 - -struct VoxelGIData { - mat4 xform; - vec3 bounds; - float dynamic_range; +global_variables; - float bias; - float normal_bias; - bool blend_ambient; - uint texture_slot; - - float anisotropy_strength; - float ambient_occlusion; - float ambient_occlusion_size; - uint mipmaps; -}; - -layout(set = 0, binding = 11, std140) uniform VoxelGIs { - VoxelGIData data[MAX_VOXEL_GI_INSTANCES]; -} -voxel_gi_instances; - -layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; - -layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps; - -#ifdef ENABLE_SDFGI - -// SDFGI Integration on set 1 -#define SDFGI_MAX_CASCADES 8 - -struct SDFVoxelGICascadeData { +layout(push_constant, binding = 0, std430) uniform Params { vec3 position; - float to_probe; - ivec3 probe_world_offset; - float to_cell; // 1/bounds * grid_size -}; - -layout(set = 1, binding = 0, std140) uniform SDFGI { - vec3 grid_size; - uint max_cascades; - - bool use_occlusion; - int probe_axis_size; - float probe_to_uvw; - float normal_bias; + float pad; - vec3 lightprobe_tex_pixel_size; - float energy; + vec3 extents; + float pad2; - vec3 lightprobe_uv_offset; - float y_mult; + ivec3 corner; + uint shape; - vec3 occlusion_clamp; - uint pad3; - - vec3 occlusion_renormalize; - uint pad4; - - vec3 cascade_probe_size; - uint pad5; - - SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES]; + mat4 transform; } -sdfgi; - -layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture; - -layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture; +params; -#endif //SDFGI +#ifdef MOLTENVK_USED +layout(set = 1, binding = 1) volatile buffer emissive_only_map_buffer { + uint emissive_only_map[]; +}; +#else +layout(r32ui, set = 1, binding = 1) uniform volatile uimage3D emissive_only_map; +#endif -layout(set = 0, binding = 14, std140) uniform Params { +layout(set = 1, binding = 2, std140) uniform SceneParams { vec2 fog_frustum_size_begin; vec2 fog_frustum_size_end; float fog_frustum_end; - float z_near; - float z_far; - int filter_axis; + float z_near; // + float z_far; // + float time; ivec3 fog_volume_size; - uint directional_light_count; - - vec3 light_color; - float base_density; - - float detail_spread; - float gi_inject; - uint max_voxel_gi_instances; - uint cluster_type_size; + uint directional_light_count; // - vec2 screen_size; - uint cluster_shift; - uint cluster_width; - - uint max_cluster_element_count_div_32; bool use_temporal_reprojection; uint temporal_frame; + float detail_spread; float temporal_blend; - mat3x4 cam_rotation; mat4 to_prev_view; + mat4 transform; } -params; - -layout(set = 0, binding = 15) uniform texture3D prev_density_texture; +scene_params; -float get_depth_at_pos(float cell_depth_size, int z) { - float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels - d = pow(d, params.detail_spread); - return params.fog_frustum_end * d; -} - -vec3 hash3f(uvec3 x) { - x = ((x >> 16) ^ x) * 0x45d9f3b; - x = ((x >> 16) ^ x) * 0x45d9f3b; - x = (x >> 16) ^ x; - return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF)); -} - -float get_omni_attenuation(float distance, float inv_range, float decay) { - float nd = distance * inv_range; - nd *= nd; - nd *= nd; // nd^4 - nd = max(1.0 - nd, 0.0); - nd *= nd; // nd^2 - return nd * pow(max(distance, 0.0001), -decay); -} +#ifdef MOLTENVK_USED +layout(set = 1, binding = 3) volatile buffer density_only_map_buffer { + uint density_only_map[]; +}; +layout(set = 1, binding = 4) volatile buffer light_only_map_buffer { + uint light_only_map[]; +}; +#else +layout(r32ui, set = 1, binding = 3) uniform volatile uimage3D density_only_map; +layout(r32ui, set = 1, binding = 4) uniform volatile uimage3D light_only_map; +#endif -void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { - uint item_min_max = cluster_buffer.data[p_offset]; - item_min = item_min_max & 0xFFFF; - item_max = item_min_max >> 16; - ; +#ifdef MATERIAL_UNIFORMS_USED +layout(set = 2, binding = 0, std140) uniform MaterialUniforms{ +#MATERIAL_UNIFORMS +} material; +#endif - item_from = item_min >> 5; - item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements -} +#GLOBALS -uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { - int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); - int mask_width = min(int(z_max) - int(z_min), 32 - local_min); - return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +float get_depth_at_pos(float cell_depth_size, int z) { + float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels + d = pow(d, scene_params.detail_spread); + return scene_params.fog_frustum_end * d; } #define TEMPORAL_FRAMES 16 @@ -240,464 +124,167 @@ const vec3 halton_map[TEMPORAL_FRAMES] = vec3[]( vec3(0.03125, 0.59259259, 0.32)); void main() { - vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size); + vec3 fog_cell_size = 1.0 / vec3(scene_params.fog_volume_size); -#ifdef MODE_DENSITY - - ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); - if (any(greaterThanEqual(pos, params.fog_volume_size))) { + ivec3 pos = ivec3(gl_GlobalInvocationID.xyz) + params.corner; + if (any(greaterThanEqual(pos, scene_params.fog_volume_size))) { return; //do not compute } +#ifdef MOLTENVK_USED + uint lpos = pos.z * scene_params.fog_volume_size.x * scene_params.fog_volume_size.y + pos.y * scene_params.fog_volume_size.x + pos.x; +#endif vec3 posf = vec3(pos); - //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0; - vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels - - uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); - uvec2 cluster_pos = screen_pos >> params.cluster_shift; - uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); - //positions in screen are too spread apart, no hopes for optimizing with subgroups - - fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); + fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread); vec3 view_pos; - view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z)); - view_pos.z = -params.fog_frustum_end * fog_unit_pos.z; + view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z)); + view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z; view_pos.y = -view_pos.y; - vec4 reprojected_density = vec4(0.0); - float reproject_amount = 0.0; - - if (params.use_temporal_reprojection) { - vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz; + if (scene_params.use_temporal_reprojection) { + vec3 prev_view = (scene_params.to_prev_view * vec4(view_pos, 1.0)).xyz; //undo transform into prev view prev_view.y = -prev_view.y; //z back to unit size - prev_view.z /= -params.fog_frustum_end; + prev_view.z /= -scene_params.fog_frustum_end; //xy back to unit size - prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z)); + prev_view.xy /= mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(prev_view.z)); prev_view.xy = prev_view.xy * 0.5 + 0.5; //z back to unspread value - prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread); + prev_view.z = pow(prev_view.z, 1.0 / scene_params.detail_spread); if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) { //reprojectinon fits - - reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0); - reproject_amount = params.temporal_blend; - // Since we can reproject, now we must jitter the current view pos. // This is done here because cells that can't reproject should not jitter. - fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table - - screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); - cluster_pos = screen_pos >> params.cluster_shift; - cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); - //positions in screen are too spread apart, no hopes for optimizing with subgroups + fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[scene_params.temporal_frame]; //center of voxels, offset by halton table + fog_unit_pos.z = pow(fog_unit_pos.z, scene_params.detail_spread); - fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); - - view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z)); - view_pos.z = -params.fog_frustum_end * fog_unit_pos.z; + view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(scene_params.fog_frustum_size_begin, scene_params.fog_frustum_size_end, vec2(fog_unit_pos.z)); + view_pos.z = -scene_params.fog_frustum_end * fog_unit_pos.z; view_pos.y = -view_pos.y; } } - uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0)); - - vec3 total_light = params.light_color; + float density = 0.0; + vec3 emission = vec3(0.0); + vec3 albedo = vec3(0.0); - float total_density = params.base_density; float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1)); - //compute directional lights - - for (uint i = 0; i < params.directional_light_count; i++) { - vec3 shadow_attenuation = vec3(1.0); - - if (directional_lights.data[i].shadow_enabled) { - float depth_z = -view_pos.z; - - vec4 pssm_coord; - vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb; - vec3 light_dir = directional_lights.data[i].direction; - vec4 v = vec4(view_pos, 1.0); - float z_range; - - if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { - pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); - pssm_coord /= pssm_coord.w; - z_range = directional_lights.data[i].shadow_z_range.x; - - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { - pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); - pssm_coord /= pssm_coord.w; - z_range = directional_lights.data[i].shadow_z_range.y; - - } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { - pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); - pssm_coord /= pssm_coord.w; - z_range = directional_lights.data[i].shadow_z_range.z; - - } else { - pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); - pssm_coord /= pssm_coord.w; - z_range = directional_lights.data[i].shadow_z_range.w; - } - - float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r; - float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade); - - /* - //float shadow = textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord); - float shadow = 0.0; - for(float xi=-1;xi<=1;xi++) { - for(float yi=-1;yi<=1;yi++) { - vec2 ofs = vec2(xi,yi) * 1.5 * params.directional_shadow_pixel_size; - shadow += textureProj(sampler2DShadow(directional_shadow_atlas,shadow_sampler),pssm_coord + vec4(ofs,0.0,0.0)); - } - - } - - shadow /= 3.0 * 3.0; -*/ - shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance - - shadow_attenuation = mix(shadow_color, vec3(1.0), shadow); - } - - total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy / M_PI; + vec4 world = scene_params.transform * vec4(view_pos, 1.0); + world.xyz /= world.w; + + vec3 uvw = fog_unit_pos; + + vec4 local_pos = params.transform * world; + local_pos.xyz /= local_pos.w; + + float sdf = -1.0; + if (params.shape == 0) { + //Ellipsoid + // https://www.shadertoy.com/view/tdS3DG + float k0 = length(local_pos.xyz / params.extents); + float k1 = length(local_pos.xyz / (params.extents * params.extents)); + sdf = k0 * (k0 - 1.0) / k1; + } else if (params.shape == 1) { + // Box + // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm + vec3 q = abs(local_pos.xyz) - params.extents; + sdf = length(max(q, 0.0)) + min(max(q.x, max(q.y, q.z)), 0.0); } - //compute lights from cluster - - { //omni lights - - uint cluster_omni_offset = cluster_offset; - - uint item_min; - uint item_max; - uint item_from; - uint item_to; - - cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - -#ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); + float cull_mask = 1.0; //used to cull cells that do not contribute + if (params.shape <= 1) { +#ifndef SDF_USED + cull_mask = 1.0 - smoothstep(-0.1, 0.0, sdf); #endif + uvw = clamp((local_pos.xyz + params.extents) / (2.0 * params.extents), 0.0, 1.0); + } - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_omni_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); -#ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); + if (cull_mask > 0.0) { + { +#CODE : FOG + } + +#ifdef DENSITY_USED + density *= cull_mask; + if (abs(density) > 0.001) { + int final_density = int(density * DENSITY_SCALE); +#ifdef MOLTENVK_USED + atomicAdd(density_only_map[lpos], uint(final_density)); #else - uint merged_mask = mask; + imageAtomicAdd(density_only_map, pos, uint(final_density)); #endif - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); -#ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } +#ifdef EMISSION_USED + { + emission *= clamp(density, 0.0, 1.0); + emission = clamp(emission, vec3(0.0), vec3(4.0)); + // Scale to fit into R11G11B10 with a range of 0-4 + uvec3 emission_u = uvec3(emission.r * 511.0, emission.g * 511.0, emission.b * 255.0); + // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint + uint final_emission = emission_u.r << 21 | emission_u.g << 10 | emission_u.b; +#ifdef MOLTENVK_USED + uint prev_emission = atomicAdd(emissive_only_map[lpos], final_emission); +#else + uint prev_emission = imageAtomicAdd(emissive_only_map, pos, final_emission); #endif - uint light_index = 32 * i + bit; - - //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) { - // continue; //not masked - //} - - vec3 light_pos = omni_lights.data[light_index].position; - float d = distance(omni_lights.data[light_index].position, view_pos); - float shadow_attenuation = 1.0; - - if (d * omni_lights.data[light_index].inv_radius < 1.0) { - float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation); - - vec3 light = omni_lights.data[light_index].color / M_PI; - - if (omni_lights.data[light_index].shadow_enabled) { - //has shadow - vec4 v = vec4(view_pos, 1.0); - - vec4 splane = (omni_lights.data[light_index].shadow_matrix * v); - float shadow_len = length(splane.xyz); //need to remember shadow len from here - splane.xyz = normalize(splane.xyz); - vec4 clamp_rect = omni_lights.data[light_index].atlas_rect; + // Adding can lead to colors overflowing, so validate + uvec3 prev_emission_u = uvec3(prev_emission >> 21, (prev_emission << 11) >> 21, prev_emission % 1024); + uint add_emission = final_emission + prev_emission; + uvec3 add_emission_u = uvec3(add_emission >> 21, (add_emission << 11) >> 21, add_emission % 1024); - if (splane.z >= 0.0) { - splane.z += 1.0; + bvec3 overflowing = lessThan(add_emission_u, prev_emission_u + emission_u); - clamp_rect.y += clamp_rect.w; - - } else { - splane.z = 1.0 - splane.z; - } - - splane.xy /= splane.z; - - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len * omni_lights.data[light_index].inv_radius; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; - splane.w = 1.0; //needed? i think it should be 1 already - - float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; - - shadow_attenuation = exp(min(0.0, (depth - splane.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade); - } - total_light += light * attenuation * shadow_attenuation; + if (any(overflowing)) { + uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing); + uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b; +#ifdef MOLTENVK_USED + atomicOr(emissive_only_map[lpos], force_max); +#else + imageAtomicOr(emissive_only_map, pos, force_max); +#endif } } - } - } - - { //spot lights - - uint cluster_spot_offset = cluster_offset + params.cluster_type_size; - - uint item_min; - uint item_max; - uint item_from; - uint item_to; - - cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); - -#ifdef USE_SUBGROUPS - item_from = subgroupBroadcastFirst(subgroupMin(item_from)); - item_to = subgroupBroadcastFirst(subgroupMax(item_to)); #endif - - for (uint i = item_from; i < item_to; i++) { - uint mask = cluster_buffer.data[cluster_spot_offset + i]; - mask &= cluster_get_range_clip_mask(i, item_min, item_max); -#ifdef USE_SUBGROUPS - uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#ifdef ALBEDO_USED + { + vec3 scattering = albedo * clamp(density, 0.0, 1.0); + scattering = clamp(scattering, vec3(0.0), vec3(1.0)); + uvec3 scattering_u = uvec3(scattering.r * 2047.0, scattering.g * 2047.0, scattering.b * 1023.0); + // R and G have 11 bits each and B has 10. Then pack them into a 32 bit uint + uint final_scattering = scattering_u.r << 21 | scattering_u.g << 10 | scattering_u.b; +#ifdef MOLTENVK_USED + uint prev_scattering = atomicAdd(light_only_map[lpos], final_scattering); #else - uint merged_mask = mask; -#endif - - while (merged_mask != 0) { - uint bit = findMSB(merged_mask); - merged_mask &= ~(1 << bit); -#ifdef USE_SUBGROUPS - if (((1 << bit) & mask) == 0) { //do not process if not originally here - continue; - } + uint prev_scattering = imageAtomicAdd(light_only_map, pos, final_scattering); #endif - //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) { - // continue; //not masked - //} - - uint light_index = 32 * i + bit; - - vec3 light_pos = spot_lights.data[light_index].position; - vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos; - float d = length(light_rel_vec); - float shadow_attenuation = 1.0; - - if (d * spot_lights.data[light_index].inv_radius < 1.0) { - float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation); - - vec3 spot_dir = spot_lights.data[light_index].direction; - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle)); - attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation); - - vec3 light = spot_lights.data[light_index].color / M_PI; - - if (spot_lights.data[light_index].shadow_enabled) { - //has shadow - vec4 v = vec4(view_pos, 1.0); - - vec4 splane = (spot_lights.data[light_index].shadow_matrix * v); - splane /= splane.w; - - float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; - - shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); - } - - total_light += light * attenuation * shadow_attenuation; - } - } - } - } - - vec3 world_pos = mat3(params.cam_rotation) * view_pos; - - for (uint i = 0; i < params.max_voxel_gi_instances; i++) { - vec3 position = (voxel_gi_instances.data[i].xform * vec4(world_pos, 1.0)).xyz; - - //this causes corrupted pixels, i have no idea why.. - if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, voxel_gi_instances.data[i].bounds))))) { - position /= voxel_gi_instances.data[i].bounds; - - vec4 light = vec4(0.0); - for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) { - vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j)); - float a = (1.0 - light.a); - light += a * slight; - } - - light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject; - - total_light += light.rgb; - } - } - - //sdfgi -#ifdef ENABLE_SDFGI + // Adding can lead to colors overflowing, so validate + uvec3 prev_scattering_u = uvec3(prev_scattering >> 21, (prev_scattering << 11) >> 21, prev_scattering % 1024); + uint add_scattering = final_scattering + prev_scattering; + uvec3 add_scattering_u = uvec3(add_scattering >> 21, (add_scattering << 11) >> 21, add_scattering % 1024); - { - float blend = -1.0; - vec3 ambient_total = vec3(0.0); + bvec3 overflowing = lessThan(add_scattering_u, prev_scattering_u + scattering_u); - for (uint i = 0; i < sdfgi.max_cascades; i++) { - vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe; - - if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) { - continue; //skip cascade - } - - vec3 base_pos = floor(cascade_pos); - ivec3 probe_base_pos = ivec3(base_pos); - - vec4 ambient_accum = vec4(0.0); - - ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i)); - tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size; - - for (uint j = 0; j < 8; j++) { - ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); - ivec3 probe_posi = probe_base_pos; - probe_posi += offset; - - // Compute weight - - vec3 probe_pos = vec3(probe_posi); - vec3 probe_to_pos = cascade_pos - probe_pos; - - vec3 trilinear = vec3(1.0) - abs(probe_to_pos); - float weight = trilinear.x * trilinear.y * trilinear.z; - - // Compute lightprobe occlusion - - if (sdfgi.use_occlusion) { - ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4); - vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3))); - - vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw; - occ_pos.z += float(i); - if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures - occ_pos.x += 1.0; - } - - occ_pos *= sdfgi.occlusion_renormalize; - float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask); - - weight *= max(occlusion, 0.01); + if (any(overflowing)) { + uvec3 overflow_factor = mix(uvec3(0), uvec3(2047 << 21, 2047 << 10, 1023), overflowing); + uint force_max = overflow_factor.r | overflow_factor.g | overflow_factor.b; +#ifdef MOLTENVK_USED + atomicOr(light_only_map[lpos], force_max); +#else + imageAtomicOr(light_only_map, pos, force_max); +#endif } - - // Compute ambient texture position - - ivec3 uvw = tex_pos; - uvw.xy += offset.xy; - uvw.x += offset.z * sdfgi.probe_axis_size; - - vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb; - - ambient_accum.rgb += ambient * weight; - ambient_accum.a += weight; - } - - if (ambient_accum.a > 0) { - ambient_accum.rgb /= ambient_accum.a; } - ambient_total = ambient_accum.rgb; - break; +#endif // ALBEDO_USED } - - total_light += ambient_total * params.gi_inject; +#endif // DENSITY_USED } - -#endif - - vec4 final_density = vec4(total_light, total_density); - - final_density = mix(final_density, reprojected_density, reproject_amount); - - imageStore(density_map, pos, final_density); -#endif - -#ifdef MODE_FOG - - ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0); - - if (any(greaterThanEqual(pos, params.fog_volume_size))) { - return; //do not compute - } - - vec4 fog_accum = vec4(0.0); - float prev_z = 0.0; - - float t = 1.0; - - for (int i = 0; i < params.fog_volume_size.z; i++) { - //compute fog position - ivec3 fog_pos = pos + ivec3(0, 0, i); - //get fog value - vec4 fog = imageLoad(density_map, fog_pos); - - //get depth at cell pos - float z = get_depth_at_pos(fog_cell_size.z, i); - //get distance from previous pos - float d = abs(prev_z - z); - //compute exinction based on beer's - float extinction = t * exp(-d * fog.a); - //compute alpha based on different of extinctions - float alpha = t - extinction; - //update extinction - t = extinction; - - fog_accum += vec4(fog.rgb * alpha, alpha); - prev_z = z; - - vec4 fog_value; - - if (fog_accum.a > 0.0) { - fog_value = vec4(fog_accum.rgb / fog_accum.a, 1.0 - t); - } else { - fog_value = vec4(0.0); - } - - imageStore(fog_map, fog_pos, fog_value); - } - -#endif - -#ifdef MODE_FILTER - - ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); - - const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303); - - const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1)); - ivec3 offset = filter_dir[params.filter_axis]; - - vec4 accum = vec4(0.0); - for (int i = -3; i <= 3; i++) { - accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3]; - } - - imageStore(dest_map, pos, accum); - -#endif } diff --git a/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl new file mode 100644 index 0000000000..747f88960c --- /dev/null +++ b/servers/rendering/renderer_rd/shaders/volumetric_fog_process.glsl @@ -0,0 +1,776 @@ +#[compute] + +#version 450 + +#VERSION_DEFINES + +/* Do not use subgroups here, seems there is not much advantage and causes glitches +#if defined(has_GL_KHR_shader_subgroup_ballot) && defined(has_GL_KHR_shader_subgroup_arithmetic) +#extension GL_KHR_shader_subgroup_ballot: enable +#extension GL_KHR_shader_subgroup_arithmetic: enable + +#define USE_SUBGROUPS +#endif +*/ + +#ifdef MODE_DENSITY +layout(local_size_x = 4, local_size_y = 4, local_size_z = 4) in; +#else +layout(local_size_x = 8, local_size_y = 8, local_size_z = 1) in; +#endif + +#include "cluster_data_inc.glsl" +#include "light_data_inc.glsl" + +#define M_PI 3.14159265359 + +#define DENSITY_SCALE 1024.0 + +layout(set = 0, binding = 1) uniform texture2D shadow_atlas; +layout(set = 0, binding = 2) uniform texture2D directional_shadow_atlas; + +layout(set = 0, binding = 3, std430) restrict readonly buffer OmniLights { + LightData data[]; +} +omni_lights; + +layout(set = 0, binding = 4, std430) restrict readonly buffer SpotLights { + LightData data[]; +} +spot_lights; + +layout(set = 0, binding = 5, std140) uniform DirectionalLights { + DirectionalLightData data[MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS]; +} +directional_lights; + +layout(set = 0, binding = 6, std430) buffer restrict readonly ClusterBuffer { + uint data[]; +} +cluster_buffer; + +layout(set = 0, binding = 7) uniform sampler linear_sampler; + +#ifdef MODE_DENSITY +layout(rgba16f, set = 0, binding = 8) uniform restrict writeonly image3D density_map; +layout(rgba16f, set = 0, binding = 9) uniform restrict readonly image3D fog_map; //unused +#endif + +#ifdef MODE_FOG +layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D density_map; +layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D fog_map; +#endif + +#ifdef MODE_COPY +layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map; +layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map; +#endif + +#ifdef MODE_FILTER +layout(rgba16f, set = 0, binding = 8) uniform restrict readonly image3D source_map; +layout(rgba16f, set = 0, binding = 9) uniform restrict writeonly image3D dest_map; +#endif + +layout(set = 0, binding = 10) uniform sampler shadow_sampler; + +#define MAX_VOXEL_GI_INSTANCES 8 + +struct VoxelGIData { + mat4 xform; + vec3 bounds; + float dynamic_range; + + float bias; + float normal_bias; + bool blend_ambient; + uint texture_slot; + + float anisotropy_strength; + float ambient_occlusion; + float ambient_occlusion_size; + uint mipmaps; +}; + +layout(set = 0, binding = 11, std140) uniform VoxelGIs { + VoxelGIData data[MAX_VOXEL_GI_INSTANCES]; +} +voxel_gi_instances; + +layout(set = 0, binding = 12) uniform texture3D voxel_gi_textures[MAX_VOXEL_GI_INSTANCES]; + +layout(set = 0, binding = 13) uniform sampler linear_sampler_with_mipmaps; + +#ifdef ENABLE_SDFGI + +// SDFGI Integration on set 1 +#define SDFGI_MAX_CASCADES 8 + +struct SDFVoxelGICascadeData { + vec3 position; + float to_probe; + ivec3 probe_world_offset; + float to_cell; // 1/bounds * grid_size +}; + +layout(set = 1, binding = 0, std140) uniform SDFGI { + vec3 grid_size; + uint max_cascades; + + bool use_occlusion; + int probe_axis_size; + float probe_to_uvw; + float normal_bias; + + vec3 lightprobe_tex_pixel_size; + float energy; + + vec3 lightprobe_uv_offset; + float y_mult; + + vec3 occlusion_clamp; + uint pad3; + + vec3 occlusion_renormalize; + uint pad4; + + vec3 cascade_probe_size; + uint pad5; + + SDFVoxelGICascadeData cascades[SDFGI_MAX_CASCADES]; +} +sdfgi; + +layout(set = 1, binding = 1) uniform texture2DArray sdfgi_ambient_texture; + +layout(set = 1, binding = 2) uniform texture3D sdfgi_occlusion_texture; + +#endif //SDFGI + +layout(set = 0, binding = 14, std140) uniform Params { + vec2 fog_frustum_size_begin; + vec2 fog_frustum_size_end; + + float fog_frustum_end; + float ambient_inject; + float z_far; + int filter_axis; + + vec3 ambient_color; + float sky_contribution; + + ivec3 fog_volume_size; + uint directional_light_count; + + vec3 base_emission; + float base_density; + + vec3 base_scattering; + float phase_g; + + float detail_spread; + float gi_inject; + uint max_voxel_gi_instances; + uint cluster_type_size; + + vec2 screen_size; + uint cluster_shift; + uint cluster_width; + + uint max_cluster_element_count_div_32; + bool use_temporal_reprojection; + uint temporal_frame; + float temporal_blend; + + mat3x4 cam_rotation; + mat4 to_prev_view; + + mat3 radiance_inverse_xform; +} +params; +#ifndef MODE_COPY +layout(set = 0, binding = 15) uniform texture3D prev_density_texture; + +#ifdef MOLTENVK_USED +layout(set = 0, binding = 16) buffer density_only_map_buffer { + uint density_only_map[]; +}; +layout(set = 0, binding = 17) buffer light_only_map_buffer { + uint light_only_map[]; +}; +layout(set = 0, binding = 18) buffer emissive_only_map_buffer { + uint emissive_only_map[]; +}; +#else +layout(r32ui, set = 0, binding = 16) uniform uimage3D density_only_map; +layout(r32ui, set = 0, binding = 17) uniform uimage3D light_only_map; +layout(r32ui, set = 0, binding = 18) uniform uimage3D emissive_only_map; +#endif + +#ifdef USE_RADIANCE_CUBEMAP_ARRAY +layout(set = 0, binding = 19) uniform textureCubeArray sky_texture; +#else +layout(set = 0, binding = 19) uniform textureCube sky_texture; +#endif +#endif // MODE_COPY + +float get_depth_at_pos(float cell_depth_size, int z) { + float d = float(z) * cell_depth_size + cell_depth_size * 0.5; //center of voxels + d = pow(d, params.detail_spread); + return params.fog_frustum_end * d; +} + +vec3 hash3f(uvec3 x) { + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = ((x >> 16) ^ x) * 0x45d9f3b; + x = (x >> 16) ^ x; + return vec3(x & 0xFFFFF) / vec3(float(0xFFFFF)); +} + +float get_omni_attenuation(float dist, float inv_range, float decay) { + float nd = dist * inv_range; + nd *= nd; + nd *= nd; // nd^4 + nd = max(1.0 - nd, 0.0); + nd *= nd; // nd^2 + return nd * pow(max(dist, 0.0001), -decay); +} + +void cluster_get_item_range(uint p_offset, out uint item_min, out uint item_max, out uint item_from, out uint item_to) { + uint item_min_max = cluster_buffer.data[p_offset]; + item_min = item_min_max & 0xFFFF; + item_max = item_min_max >> 16; + ; + + item_from = item_min >> 5; + item_to = (item_max == 0) ? 0 : ((item_max - 1) >> 5) + 1; //side effect of how it is stored, as item_max 0 means no elements +} + +uint cluster_get_range_clip_mask(uint i, uint z_min, uint z_max) { + int local_min = clamp(int(z_min) - int(i) * 32, 0, 31); + int mask_width = min(int(z_max) - int(z_min), 32 - local_min); + return bitfieldInsert(uint(0), uint(0xFFFFFFFF), local_min, mask_width); +} + +float henyey_greenstein(float cos_theta, float g) { + const float k = 0.0795774715459; // 1 / (4 * PI) + return k * (1.0 - g * g) / (pow(1.0 + g * g - 2.0 * g * cos_theta, 1.5)); +} + +#define TEMPORAL_FRAMES 16 + +const vec3 halton_map[TEMPORAL_FRAMES] = vec3[]( + vec3(0.5, 0.33333333, 0.2), + vec3(0.25, 0.66666667, 0.4), + vec3(0.75, 0.11111111, 0.6), + vec3(0.125, 0.44444444, 0.8), + vec3(0.625, 0.77777778, 0.04), + vec3(0.375, 0.22222222, 0.24), + vec3(0.875, 0.55555556, 0.44), + vec3(0.0625, 0.88888889, 0.64), + vec3(0.5625, 0.03703704, 0.84), + vec3(0.3125, 0.37037037, 0.08), + vec3(0.8125, 0.7037037, 0.28), + vec3(0.1875, 0.14814815, 0.48), + vec3(0.6875, 0.48148148, 0.68), + vec3(0.4375, 0.81481481, 0.88), + vec3(0.9375, 0.25925926, 0.12), + vec3(0.03125, 0.59259259, 0.32)); + +void main() { + vec3 fog_cell_size = 1.0 / vec3(params.fog_volume_size); + +#ifdef MODE_DENSITY + + ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); + if (any(greaterThanEqual(pos, params.fog_volume_size))) { + return; //do not compute + } +#ifdef MOLTENVK_USED + uint lpos = pos.z * params.fog_volume_size.x * params.fog_volume_size.y + pos.y * params.fog_volume_size.x + pos.x; +#endif + + vec3 posf = vec3(pos); + + //posf += mix(vec3(0.0),vec3(1.0),0.3) * hash3f(uvec3(pos)) * 2.0 - 1.0; + + vec3 fog_unit_pos = posf * fog_cell_size + fog_cell_size * 0.5; //center of voxels + + uvec2 screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); + uvec2 cluster_pos = screen_pos >> params.cluster_shift; + uint cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); + //positions in screen are too spread apart, no hopes for optimizing with subgroups + + fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); + + vec3 view_pos; + view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z)); + view_pos.z = -params.fog_frustum_end * fog_unit_pos.z; + view_pos.y = -view_pos.y; + + vec4 reprojected_density = vec4(0.0); + float reproject_amount = 0.0; + + if (params.use_temporal_reprojection) { + vec3 prev_view = (params.to_prev_view * vec4(view_pos, 1.0)).xyz; + //undo transform into prev view + prev_view.y = -prev_view.y; + //z back to unit size + prev_view.z /= -params.fog_frustum_end; + //xy back to unit size + prev_view.xy /= mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(prev_view.z)); + prev_view.xy = prev_view.xy * 0.5 + 0.5; + //z back to unspread value + prev_view.z = pow(prev_view.z, 1.0 / params.detail_spread); + + if (all(greaterThan(prev_view, vec3(0.0))) && all(lessThan(prev_view, vec3(1.0)))) { + //reprojectinon fits + + reprojected_density = textureLod(sampler3D(prev_density_texture, linear_sampler), prev_view, 0.0); + reproject_amount = params.temporal_blend; + + // Since we can reproject, now we must jitter the current view pos. + // This is done here because cells that can't reproject should not jitter. + + fog_unit_pos = posf * fog_cell_size + fog_cell_size * halton_map[params.temporal_frame]; //center of voxels, offset by halton table + + screen_pos = uvec2(fog_unit_pos.xy * params.screen_size); + cluster_pos = screen_pos >> params.cluster_shift; + cluster_offset = (params.cluster_width * cluster_pos.y + cluster_pos.x) * (params.max_cluster_element_count_div_32 + 32); + //positions in screen are too spread apart, no hopes for optimizing with subgroups + + fog_unit_pos.z = pow(fog_unit_pos.z, params.detail_spread); + + view_pos.xy = (fog_unit_pos.xy * 2.0 - 1.0) * mix(params.fog_frustum_size_begin, params.fog_frustum_size_end, vec2(fog_unit_pos.z)); + view_pos.z = -params.fog_frustum_end * fog_unit_pos.z; + view_pos.y = -view_pos.y; + } + } + + uint cluster_z = uint(clamp((abs(view_pos.z) / params.z_far) * 32.0, 0.0, 31.0)); + + vec3 total_light = vec3(0.0); + + float total_density = params.base_density; +#ifdef MOLTENVK_USED + uint local_density = density_only_map[lpos]; +#else + uint local_density = imageLoad(density_only_map, pos).x; +#endif + + total_density += float(int(local_density)) / DENSITY_SCALE; + total_density = max(0.0, total_density); + +#ifdef MOLTENVK_USED + uint scattering_u = light_only_map[lpos]; +#else + uint scattering_u = imageLoad(light_only_map, pos).x; +#endif + vec3 scattering = vec3(scattering_u >> 21, (scattering_u << 11) >> 21, scattering_u % 1024) / vec3(2047.0, 2047.0, 1023.0); + scattering += params.base_scattering * params.base_density; + +#ifdef MOLTENVK_USED + uint emission_u = emissive_only_map[lpos]; +#else + uint emission_u = imageLoad(emissive_only_map, pos).x; +#endif + vec3 emission = vec3(emission_u >> 21, (emission_u << 11) >> 21, emission_u % 1024) / vec3(511.0, 511.0, 255.0); + emission += params.base_emission * params.base_density; + + float cell_depth_size = abs(view_pos.z - get_depth_at_pos(fog_cell_size.z, pos.z + 1)); + //compute directional lights + + if (total_density > 0.001) { + for (uint i = 0; i < params.directional_light_count; i++) { + vec3 shadow_attenuation = vec3(1.0); + + if (directional_lights.data[i].shadow_enabled) { + float depth_z = -view_pos.z; + + vec4 pssm_coord; + vec3 shadow_color = directional_lights.data[i].shadow_color1.rgb; + vec3 light_dir = directional_lights.data[i].direction; + vec4 v = vec4(view_pos, 1.0); + float z_range; + + if (depth_z < directional_lights.data[i].shadow_split_offsets.x) { + pssm_coord = (directional_lights.data[i].shadow_matrix1 * v); + pssm_coord /= pssm_coord.w; + z_range = directional_lights.data[i].shadow_z_range.x; + + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.y) { + pssm_coord = (directional_lights.data[i].shadow_matrix2 * v); + pssm_coord /= pssm_coord.w; + z_range = directional_lights.data[i].shadow_z_range.y; + + } else if (depth_z < directional_lights.data[i].shadow_split_offsets.z) { + pssm_coord = (directional_lights.data[i].shadow_matrix3 * v); + pssm_coord /= pssm_coord.w; + z_range = directional_lights.data[i].shadow_z_range.z; + + } else { + pssm_coord = (directional_lights.data[i].shadow_matrix4 * v); + pssm_coord /= pssm_coord.w; + z_range = directional_lights.data[i].shadow_z_range.w; + } + + float depth = texture(sampler2D(directional_shadow_atlas, linear_sampler), pssm_coord.xy).r; + float shadow = exp(min(0.0, (depth - pssm_coord.z)) * z_range * directional_lights.data[i].shadow_volumetric_fog_fade); + + shadow = mix(shadow, 1.0, smoothstep(directional_lights.data[i].fade_from, directional_lights.data[i].fade_to, view_pos.z)); //done with negative values for performance + + shadow_attenuation = mix(shadow_color, vec3(1.0), shadow); + } + + total_light += shadow_attenuation * directional_lights.data[i].color * directional_lights.data[i].energy * henyey_greenstein(dot(normalize(view_pos), normalize(directional_lights.data[i].direction)), params.phase_g); + } + + // Compute light from sky + if (params.ambient_inject > 0.0) { + vec3 isotropic = vec3(0.0); + vec3 anisotropic = vec3(0.0); + if (params.sky_contribution > 0.0) { + float mip_bias = 2.0 + total_density * (MAX_SKY_LOD - 2.0); // Not physically based, but looks nice + vec3 scatter_direction = (params.radiance_inverse_xform * normalize(view_pos)) * sign(params.phase_g); +#ifdef USE_RADIANCE_CUBEMAP_ARRAY + isotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(0.0, 1.0, 0.0, mip_bias)).rgb; + anisotropic = texture(samplerCubeArray(sky_texture, linear_sampler_with_mipmaps), vec4(scatter_direction, mip_bias)).rgb; +#else + isotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(0.0, 1.0, 0.0), mip_bias).rgb; + anisotropic = textureLod(samplerCube(sky_texture, linear_sampler_with_mipmaps), vec3(scatter_direction), mip_bias).rgb; +#endif //USE_RADIANCE_CUBEMAP_ARRAY + } + + total_light += mix(params.ambient_color, mix(isotropic, anisotropic, abs(params.phase_g)), params.sky_contribution) * params.ambient_inject; + } + + //compute lights from cluster + + { //omni lights + + uint cluster_omni_offset = cluster_offset; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_omni_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_omni_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + uint light_index = 32 * i + bit; + + //if (!bool(omni_omni_lights.data[light_index].mask & draw_call.layer_mask)) { + // continue; //not masked + //} + + vec3 light_pos = omni_lights.data[light_index].position; + float d = distance(omni_lights.data[light_index].position, view_pos); + float shadow_attenuation = 1.0; + + if (d * omni_lights.data[light_index].inv_radius < 1.0) { + float attenuation = get_omni_attenuation(d, omni_lights.data[light_index].inv_radius, omni_lights.data[light_index].attenuation); + + vec3 light = omni_lights.data[light_index].color; + + if (omni_lights.data[light_index].shadow_enabled) { + //has shadow + vec4 uv_rect = omni_lights.data[light_index].atlas_rect; + vec2 flip_offset = omni_lights.data[light_index].direction.xy; + + vec3 local_vert = (omni_lights.data[light_index].shadow_matrix * vec4(view_pos, 1.0)).xyz; + + float shadow_len = length(local_vert); //need to remember shadow len from here + vec3 shadow_sample = normalize(local_vert); + + if (shadow_sample.z >= 0.0) { + uv_rect.xy += flip_offset; + } + + shadow_sample.z = 1.0 + abs(shadow_sample.z); + vec3 pos = vec3(shadow_sample.xy / shadow_sample.z, shadow_len - omni_lights.data[light_index].shadow_bias); + pos.z *= omni_lights.data[light_index].inv_radius; + + pos.xy = pos.xy * 0.5 + 0.5; + pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; + + float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * omni_lights.data[light_index].shadow_volumetric_fog_fade); + } + total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g); + } + } + } + } + + { //spot lights + + uint cluster_spot_offset = cluster_offset + params.cluster_type_size; + + uint item_min; + uint item_max; + uint item_from; + uint item_to; + + cluster_get_item_range(cluster_spot_offset + params.max_cluster_element_count_div_32 + cluster_z, item_min, item_max, item_from, item_to); + +#ifdef USE_SUBGROUPS + item_from = subgroupBroadcastFirst(subgroupMin(item_from)); + item_to = subgroupBroadcastFirst(subgroupMax(item_to)); +#endif + + for (uint i = item_from; i < item_to; i++) { + uint mask = cluster_buffer.data[cluster_spot_offset + i]; + mask &= cluster_get_range_clip_mask(i, item_min, item_max); +#ifdef USE_SUBGROUPS + uint merged_mask = subgroupBroadcastFirst(subgroupOr(mask)); +#else + uint merged_mask = mask; +#endif + + while (merged_mask != 0) { + uint bit = findMSB(merged_mask); + merged_mask &= ~(1 << bit); +#ifdef USE_SUBGROUPS + if (((1 << bit) & mask) == 0) { //do not process if not originally here + continue; + } +#endif + + //if (!bool(omni_lights.data[light_index].mask & draw_call.layer_mask)) { + // continue; //not masked + //} + + uint light_index = 32 * i + bit; + + vec3 light_pos = spot_lights.data[light_index].position; + vec3 light_rel_vec = spot_lights.data[light_index].position - view_pos; + float d = length(light_rel_vec); + float shadow_attenuation = 1.0; + + if (d * spot_lights.data[light_index].inv_radius < 1.0) { + float attenuation = get_omni_attenuation(d, spot_lights.data[light_index].inv_radius, spot_lights.data[light_index].attenuation); + + vec3 spot_dir = spot_lights.data[light_index].direction; + float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_lights.data[light_index].cone_angle); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_lights.data[light_index].cone_angle)); + attenuation *= 1.0 - pow(spot_rim, spot_lights.data[light_index].cone_attenuation); + + vec3 light = spot_lights.data[light_index].color; + + if (spot_lights.data[light_index].shadow_enabled) { + //has shadow + vec4 v = vec4(view_pos, 1.0); + + vec4 splane = (spot_lights.data[light_index].shadow_matrix * v); + splane /= splane.w; + + float depth = texture(sampler2D(shadow_atlas, linear_sampler), splane.xy).r; + + shadow_attenuation = exp(min(0.0, (depth - splane.z)) / spot_lights.data[light_index].inv_radius * spot_lights.data[light_index].shadow_volumetric_fog_fade); + } + + total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g); + } + } + } + } + + vec3 world_pos = mat3(params.cam_rotation) * view_pos; + + for (uint i = 0; i < params.max_voxel_gi_instances; i++) { + vec3 position = (voxel_gi_instances.data[i].xform * vec4(world_pos, 1.0)).xyz; + + //this causes corrupted pixels, i have no idea why.. + if (all(bvec2(all(greaterThanEqual(position, vec3(0.0))), all(lessThan(position, voxel_gi_instances.data[i].bounds))))) { + position /= voxel_gi_instances.data[i].bounds; + + vec4 light = vec4(0.0); + for (uint j = 0; j < voxel_gi_instances.data[i].mipmaps; j++) { + vec4 slight = textureLod(sampler3D(voxel_gi_textures[i], linear_sampler_with_mipmaps), position, float(j)); + float a = (1.0 - light.a); + light += a * slight; + } + + light.rgb *= voxel_gi_instances.data[i].dynamic_range * params.gi_inject; + + total_light += light.rgb; + } + } + + //sdfgi +#ifdef ENABLE_SDFGI + + { + float blend = -1.0; + vec3 ambient_total = vec3(0.0); + + for (uint i = 0; i < sdfgi.max_cascades; i++) { + vec3 cascade_pos = (world_pos - sdfgi.cascades[i].position) * sdfgi.cascades[i].to_probe; + + if (any(lessThan(cascade_pos, vec3(0.0))) || any(greaterThanEqual(cascade_pos, sdfgi.cascade_probe_size))) { + continue; //skip cascade + } + + vec3 base_pos = floor(cascade_pos); + ivec3 probe_base_pos = ivec3(base_pos); + + vec4 ambient_accum = vec4(0.0); + + ivec3 tex_pos = ivec3(probe_base_pos.xy, int(i)); + tex_pos.x += probe_base_pos.z * sdfgi.probe_axis_size; + + for (uint j = 0; j < 8; j++) { + ivec3 offset = (ivec3(j) >> ivec3(0, 1, 2)) & ivec3(1, 1, 1); + ivec3 probe_posi = probe_base_pos; + probe_posi += offset; + + // Compute weight + + vec3 probe_pos = vec3(probe_posi); + vec3 probe_to_pos = cascade_pos - probe_pos; + + vec3 trilinear = vec3(1.0) - abs(probe_to_pos); + float weight = trilinear.x * trilinear.y * trilinear.z; + + // Compute lightprobe occlusion + + if (sdfgi.use_occlusion) { + ivec3 occ_indexv = abs((sdfgi.cascades[i].probe_world_offset + probe_posi) & ivec3(1, 1, 1)) * ivec3(1, 2, 4); + vec4 occ_mask = mix(vec4(0.0), vec4(1.0), equal(ivec4(occ_indexv.x | occ_indexv.y), ivec4(0, 1, 2, 3))); + + vec3 occ_pos = clamp(cascade_pos, probe_pos - sdfgi.occlusion_clamp, probe_pos + sdfgi.occlusion_clamp) * sdfgi.probe_to_uvw; + occ_pos.z += float(i); + if (occ_indexv.z != 0) { //z bit is on, means index is >=4, so make it switch to the other half of textures + occ_pos.x += 1.0; + } + + occ_pos *= sdfgi.occlusion_renormalize; + float occlusion = dot(textureLod(sampler3D(sdfgi_occlusion_texture, linear_sampler), occ_pos, 0.0), occ_mask); + + weight *= max(occlusion, 0.01); + } + + // Compute ambient texture position + + ivec3 uvw = tex_pos; + uvw.xy += offset.xy; + uvw.x += offset.z * sdfgi.probe_axis_size; + + vec3 ambient = texelFetch(sampler2DArray(sdfgi_ambient_texture, linear_sampler), uvw, 0).rgb; + + ambient_accum.rgb += ambient * weight; + ambient_accum.a += weight; + } + + if (ambient_accum.a > 0) { + ambient_accum.rgb /= ambient_accum.a; + } + ambient_total = ambient_accum.rgb; + break; + } + + total_light += ambient_total * params.gi_inject; + } + +#endif + } + + vec4 final_density = vec4(total_light * scattering + emission, total_density); + + final_density = mix(final_density, reprojected_density, reproject_amount); + + imageStore(density_map, pos, final_density); +#ifdef MOLTENVK_USED + density_only_map[lpos] = 0; + light_only_map[lpos] = 0; + emissive_only_map[lpos] = 0; +#else + imageStore(density_only_map, pos, uvec4(0)); + imageStore(light_only_map, pos, uvec4(0)); + imageStore(emissive_only_map, pos, uvec4(0)); +#endif +#endif + +#ifdef MODE_FOG + + ivec3 pos = ivec3(gl_GlobalInvocationID.xy, 0); + + if (any(greaterThanEqual(pos, params.fog_volume_size))) { + return; //do not compute + } + + vec4 fog_accum = vec4(0.0, 0.0, 0.0, 1.0); + float prev_z = 0.0; + + for (int i = 0; i < params.fog_volume_size.z; i++) { + //compute fog position + ivec3 fog_pos = pos + ivec3(0, 0, i); + //get fog value + vec4 fog = imageLoad(density_map, fog_pos); + + //get depth at cell pos + float z = get_depth_at_pos(fog_cell_size.z, i); + //get distance from previous pos + float d = abs(prev_z - z); + //compute transmittance using beer's law + float transmittance = exp(-d * fog.a); + + fog_accum.rgb += ((fog.rgb - fog.rgb * transmittance) / max(fog.a, 0.00001)) * fog_accum.a; + fog_accum.a *= transmittance; + + prev_z = z; + + imageStore(fog_map, fog_pos, vec4(fog_accum.rgb, 1.0 - fog_accum.a)); + } + +#endif + +#ifdef MODE_FILTER + + ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); + + const float gauss[7] = float[](0.071303, 0.131514, 0.189879, 0.214607, 0.189879, 0.131514, 0.071303); + + const ivec3 filter_dir[3] = ivec3[](ivec3(1, 0, 0), ivec3(0, 1, 0), ivec3(0, 0, 1)); + ivec3 offset = filter_dir[params.filter_axis]; + + vec4 accum = vec4(0.0); + for (int i = -3; i <= 3; i++) { + accum += imageLoad(source_map, clamp(pos + offset * i, ivec3(0), params.fog_volume_size - ivec3(1))) * gauss[i + 3]; + } + + imageStore(dest_map, pos, accum); + +#endif +#ifdef MODE_COPY + ivec3 pos = ivec3(gl_GlobalInvocationID.xyz); + if (any(greaterThanEqual(pos, params.fog_volume_size))) { + return; //do not compute + } + + imageStore(dest_map, pos, imageLoad(source_map, pos)); + +#endif +} diff --git a/servers/rendering/renderer_scene.h b/servers/rendering/renderer_scene.h index 972637d183..02c845581c 100644 --- a/servers/rendering/renderer_scene.h +++ b/servers/rendering/renderer_scene.h @@ -76,6 +76,7 @@ public: virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) = 0; virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) = 0; virtual void instance_set_visible(RID p_instance, bool p_visible) = 0; + virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency) = 0; virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb) = 0; @@ -84,6 +85,8 @@ public: virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0; virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0; + virtual void instance_set_ignore_culling(RID p_instance, bool p_enabled) = 0; + // don't use these in a game! virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0; virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0; @@ -93,10 +96,9 @@ public: virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) = 0; virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0; - virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; + virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode) = 0; virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) = 0; virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; - virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) = 0; virtual void instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const = 0; virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const = 0; @@ -126,13 +128,13 @@ public: virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; - virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) = 0; virtual void environment_set_glow(RID p_env, bool p_enable, Vector<float> p_levels, float p_intensity, float p_strength, float p_mix, float p_bloom_threshold, RS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap) = 0; virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; - virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0; + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0; virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; @@ -189,7 +191,7 @@ public: virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index cd8014632d..5b834db178 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -47,7 +47,7 @@ void RendererSceneCull::camera_initialize(RID p_rid) { } void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->type = Camera::PERSPECTIVE; camera->fov = p_fovy_degrees; @@ -56,7 +56,7 @@ void RendererSceneCull::camera_set_perspective(RID p_camera, float p_fovy_degree } void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->type = Camera::ORTHOGONAL; camera->size = p_size; @@ -65,7 +65,7 @@ void RendererSceneCull::camera_set_orthogonal(RID p_camera, float p_size, float } void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->type = Camera::FRUSTUM; camera->size = p_size; @@ -75,32 +75,32 @@ void RendererSceneCull::camera_set_frustum(RID p_camera, float p_size, Vector2 p } void RendererSceneCull::camera_set_transform(RID p_camera, const Transform3D &p_transform) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->transform = p_transform.orthonormalized(); } void RendererSceneCull::camera_set_cull_mask(RID p_camera, uint32_t p_layers) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->visible_layers = p_layers; } void RendererSceneCull::camera_set_environment(RID p_camera, RID p_env) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->env = p_env; } void RendererSceneCull::camera_set_camera_effects(RID p_camera, RID p_fx) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->effects = p_fx; } void RendererSceneCull::camera_set_use_vertical_aspect(RID p_camera, bool p_enable) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); camera->vaspect = p_enable; } @@ -354,7 +354,7 @@ RID RendererSceneCull::scenario_allocate() { void RendererSceneCull::scenario_initialize(RID p_rid) { scenario_owner.initialize_rid(p_rid); - Scenario *scenario = scenario_owner.getornull(p_rid); + Scenario *scenario = scenario_owner.get_or_null(p_rid); scenario->self = p_rid; scenario->reflection_probe_shadow_atlas = scene_render->shadow_atlas_create(); @@ -373,25 +373,25 @@ void RendererSceneCull::scenario_initialize(RID p_rid) { } void RendererSceneCull::scenario_set_environment(RID p_scenario, RID p_environment) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); scenario->environment = p_environment; } void RendererSceneCull::scenario_set_camera_effects(RID p_scenario, RID p_camera_effects) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); scenario->camera_effects = p_camera_effects; } void RendererSceneCull::scenario_set_fallback_environment(RID p_scenario, RID p_environment) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); scenario->fallback_environment = p_environment; } void RendererSceneCull::scenario_set_reflection_atlas_size(RID p_scenario, int p_reflection_size, int p_reflection_count) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); scene_render->reflection_atlas_set_size(scenario->reflection_atlas, p_reflection_size, p_reflection_count); } @@ -401,13 +401,13 @@ bool RendererSceneCull::is_scenario(RID p_scenario) const { } RID RendererSceneCull::scenario_get_environment(RID p_scenario) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND_V(!scenario, RID()); return scenario->environment; } void RendererSceneCull::scenario_remove_viewport_visibility_mask(RID p_scenario, RID p_viewport) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); if (!scenario->viewport_visibility_masks.has(p_viewport)) { return; @@ -419,7 +419,7 @@ void RendererSceneCull::scenario_remove_viewport_visibility_mask(RID p_scenario, } void RendererSceneCull::scenario_add_viewport_visibility_mask(RID p_scenario, RID p_viewport) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); ERR_FAIL_COND(scenario->viewport_visibility_masks.has(p_viewport)); @@ -459,7 +459,7 @@ RID RendererSceneCull::instance_allocate() { } void RendererSceneCull::instance_initialize(RID p_rid) { instance_owner.initialize_rid(p_rid); - Instance *instance = instance_owner.getornull(p_rid); + Instance *instance = instance_owner.get_or_null(p_rid); instance->self = p_rid; } @@ -493,7 +493,7 @@ void RendererSceneCull::_instance_update_mesh_instance(Instance *p_instance) { } void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); Scenario *scenario = instance->scenario; @@ -540,6 +540,10 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { InstanceParticlesCollisionData *collision = static_cast<InstanceParticlesCollisionData *>(instance->base_data); RSG::storage->free(collision->instance); } break; + case RS::INSTANCE_FOG_VOLUME: { + InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(instance->base_data); + scene_render->free(volume->instance); + } break; case RS::INSTANCE_VISIBLITY_NOTIFIER: { //none } break; @@ -640,10 +644,17 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { scene_render->geometry_instance_set_use_dynamic_gi(geom->geometry_instance, instance->dynamic_gi); scene_render->geometry_instance_set_cast_double_sided_shadows(geom->geometry_instance, instance->cast_shadows == RS::SHADOW_CASTING_SETTING_DOUBLE_SIDED); scene_render->geometry_instance_set_use_lightmap(geom->geometry_instance, RID(), instance->lightmap_uv_scale, instance->lightmap_slice_index); + scene_render->geometry_instance_set_transparency(geom->geometry_instance, instance->transparency); if (instance->lightmap_sh.size() == 9) { scene_render->geometry_instance_set_lightmap_capture(geom->geometry_instance, instance->lightmap_sh.ptr()); } + for (Set<Instance *>::Element *E = instance->visibility_dependencies.front(); E; E = E->next()) { + Instance *dep_instance = E->get(); + ERR_CONTINUE(dep_instance->array_index == -1); + ERR_CONTINUE(dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index != -1); + dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = instance->array_index; + } } break; case RS::INSTANCE_PARTICLES_COLLISION: { InstanceParticlesCollisionData *collision = memnew(InstanceParticlesCollisionData); @@ -651,6 +662,12 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { RSG::storage->particles_collision_instance_set_active(collision->instance, instance->visible); instance->base_data = collision; } break; + case RS::INSTANCE_FOG_VOLUME: { + InstanceFogVolumeData *volume = memnew(InstanceFogVolumeData); + volume->instance = scene_render->fog_volume_instance_create(p_base); + scene_render->fog_volume_instance_set_active(volume->instance, instance->visible); + instance->base_data = volume; + } break; case RS::INSTANCE_VISIBLITY_NOTIFIER: { InstanceVisibilityNotifierData *vnd = memnew(InstanceVisibilityNotifierData); vnd->base = p_base; @@ -710,7 +727,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) { } void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->scenario) { @@ -772,7 +789,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { } if (p_scenario.is_valid()) { - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND(!scenario); instance->scenario = scenario; @@ -805,7 +822,7 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) { } void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->layer_mask = p_mask; @@ -819,8 +836,20 @@ void RendererSceneCull::instance_set_layer_mask(RID p_instance, uint32_t p_mask) } } +void RendererSceneCull::instance_geometry_set_transparency(RID p_instance, float p_transparency) { + Instance *instance = instance_owner.get_or_null(p_instance); + ERR_FAIL_COND(!instance); + + instance->transparency = p_transparency; + + if ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK && instance->base_data) { + InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); + scene_render->geometry_instance_set_transparency(geom->geometry_instance, p_transparency); + } +} + void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D &p_transform) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->transform == p_transform) { @@ -845,14 +874,14 @@ void RendererSceneCull::instance_set_transform(RID p_instance, const Transform3D } void RendererSceneCull::instance_attach_object_instance_id(RID p_instance, ObjectID p_id) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->object_id = p_id; } void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->update_item.in_list()) { @@ -865,7 +894,7 @@ void RendererSceneCull::instance_set_blend_shape_weight(RID p_instance, int p_sh } void RendererSceneCull::instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->base_type == RS::INSTANCE_MESH) { @@ -881,7 +910,7 @@ void RendererSceneCull::instance_set_surface_override_material(RID p_instance, i } void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->visible == p_visible) { @@ -914,6 +943,11 @@ void RendererSceneCull::instance_set_visible(RID p_instance, bool p_visible) { RSG::storage->particles_collision_instance_set_active(collision->instance, p_visible); } + if (instance->base_type == RS::INSTANCE_FOG_VOLUME) { + InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(instance->base_data); + scene_render->fog_volume_instance_set_active(volume->instance, p_visible); + } + if (instance->base_type == RS::INSTANCE_OCCLUDER) { if (instance->scenario) { RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(instance->scenario->self, p_instance, instance->base, instance->transform, p_visible); @@ -926,7 +960,7 @@ inline bool is_geometry_instance(RenderingServer::InstanceType p_type) { } void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); ERR_FAIL_COND(!is_geometry_instance(instance->base_type)); @@ -951,7 +985,7 @@ void RendererSceneCull::instance_set_custom_aabb(RID p_instance, AABB p_aabb) { } void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->skeleton == p_skeleton) { @@ -976,16 +1010,31 @@ void RendererSceneCull::instance_attach_skeleton(RID p_instance, RID p_skeleton) } void RendererSceneCull::instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->extra_margin = p_margin; _instance_queue_update(instance, true, false); } +void RendererSceneCull::instance_set_ignore_culling(RID p_instance, bool p_enabled) { + Instance *instance = instance_owner.get_or_null(p_instance); + ERR_FAIL_COND(!instance); + instance->ignore_all_culling = p_enabled; + + if (instance->scenario && instance->array_index >= 0) { + InstanceData &idata = instance->scenario->instance_data[instance->array_index]; + if (instance->ignore_all_culling) { + idata.flags |= InstanceData::FLAG_IGNORE_ALL_CULLING; + } else { + idata.flags &= ~uint32_t(InstanceData::FLAG_IGNORE_ALL_CULLING); + } + } +} + Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID p_scenario) const { Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND_V(!scenario, instances); const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling @@ -1009,7 +1058,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_aabb(const AABB &p_aabb, RID Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario) const { Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND_V(!scenario, instances); const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling @@ -1032,7 +1081,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_ray(const Vector3 &p_from, co Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p_convex, RID p_scenario) const { Vector<ObjectID> instances; - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); ERR_FAIL_COND_V(!scenario, instances); const_cast<RendererSceneCull *>(this)->update_dirty_instances(); // check dirty instances before culling @@ -1056,7 +1105,7 @@ Vector<ObjectID> RendererSceneCull::instances_cull_convex(const Vector<Plane> &p } void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceFlags p_flags, bool p_enabled) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); //ERR_FAIL_COND(((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK)); @@ -1131,7 +1180,7 @@ void RendererSceneCull::instance_geometry_set_flag(RID p_instance, RS::InstanceF } void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->cast_shadows = p_shadow_casting_setting; @@ -1139,7 +1188,7 @@ void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instanc if (instance->scenario && instance->array_index >= 0) { InstanceData &idata = instance->scenario->instance_data[instance->array_index]; - if (instance->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + if (instance->cast_shadows != RS::SHADOW_CASTING_SETTING_OFF) { idata.flags |= InstanceData::FLAG_CAST_SHADOWS; } else { idata.flags &= ~uint32_t(InstanceData::FLAG_CAST_SHADOWS); @@ -1161,7 +1210,7 @@ void RendererSceneCull::instance_geometry_set_cast_shadows_setting(RID p_instanc } void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, RID p_material) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->material_override = p_material; @@ -1173,14 +1222,15 @@ void RendererSceneCull::instance_geometry_set_material_override(RID p_instance, } } -void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) { - Instance *instance = instance_owner.getornull(p_instance); +void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode) { + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->visibility_range_begin = p_min; instance->visibility_range_end = p_max; instance->visibility_range_begin_margin = p_min_margin; instance->visibility_range_end_margin = p_max_margin; + instance->visibility_range_fade_mode = p_fade_mode; _update_instance_visibility_dependencies(instance); @@ -1190,62 +1240,58 @@ void RendererSceneCull::instance_geometry_set_visibility_range(RID p_instance, f vd.range_end = instance->visibility_range_end; vd.range_begin_margin = instance->visibility_range_begin_margin; vd.range_end_margin = instance->visibility_range_end_margin; + vd.fade_mode = p_fade_mode; } } void RendererSceneCull::instance_set_visibility_parent(RID p_instance, RID p_parent_instance) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); Instance *old_parent = instance->visibility_parent; if (old_parent) { - if ((1 << old_parent->base_type) & RS::INSTANCE_GEOMETRY_MASK && old_parent->base_data) { - InstanceGeometryData *old_parent_geom = static_cast<InstanceGeometryData *>(old_parent->base_data); - old_parent_geom->visibility_dependencies.erase(instance); - _update_instance_visibility_depth(old_parent); - } + old_parent->visibility_dependencies.erase(instance); instance->visibility_parent = nullptr; + _update_instance_visibility_depth(old_parent); } - Instance *parent = instance_owner.getornull(p_parent_instance); + Instance *parent = instance_owner.get_or_null(p_parent_instance); ERR_FAIL_COND(p_parent_instance.is_valid() && !parent); if (parent) { - if ((1 << parent->base_type) & RS::INSTANCE_GEOMETRY_MASK && parent->base_data) { - InstanceGeometryData *parent_geom = static_cast<InstanceGeometryData *>(parent->base_data); - parent_geom->visibility_dependencies.insert(instance); - _update_instance_visibility_depth(parent); - } + parent->visibility_dependencies.insert(instance); instance->visibility_parent = parent; + + bool cycle_detected = _update_instance_visibility_depth(parent); + if (cycle_detected) { + ERR_PRINT("Cycle detected in the visibility dependencies tree. The latest change to visibility_parent will have no effect."); + parent->visibility_dependencies.erase(instance); + instance->visibility_parent = nullptr; + } } _update_instance_visibility_dependencies(instance); } -void RendererSceneCull::_update_instance_visibility_depth(Instance *p_instance) { +bool RendererSceneCull::_update_instance_visibility_depth(Instance *p_instance) { bool cycle_detected = false; Set<Instance *> traversed_nodes; { Instance *instance = p_instance; - while (instance && ((1 << instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) && instance->base_data) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); - if (!geom->visibility_dependencies.is_empty()) { + while (instance) { + if (!instance->visibility_dependencies.is_empty()) { uint32_t depth = 0; - for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) { - if (((1 << E->get()->base_type) & RS::INSTANCE_GEOMETRY_MASK) == 0 || !E->get()->base_data) { - continue; - } - InstanceGeometryData *child_geom = static_cast<InstanceGeometryData *>(E->get()->base_data); - depth = MAX(depth, child_geom->visibility_dependencies_depth); + for (Set<Instance *>::Element *E = instance->visibility_dependencies.front(); E; E = E->next()) { + depth = MAX(depth, E->get()->visibility_dependencies_depth); } - geom->visibility_dependencies_depth = depth + 1; + instance->visibility_dependencies_depth = depth + 1; } else { - geom->visibility_dependencies_depth = 0; + instance->visibility_dependencies_depth = 0; } if (instance->scenario && instance->visibility_index != -1) { - instance->scenario->instance_visibility.move(instance->visibility_index, geom->visibility_dependencies_depth); + instance->scenario->instance_visibility.move(instance->visibility_index, instance->visibility_dependencies_depth); } traversed_nodes.insert(instance); @@ -1258,17 +1304,7 @@ void RendererSceneCull::_update_instance_visibility_depth(Instance *p_instance) } } - if (cycle_detected) { - ERR_PRINT("Cycle detected in the visibility dependencies tree."); - for (Set<Instance *>::Element *E = traversed_nodes.front(); E; E = E->next()) { - Instance *instance = E->get(); - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data); - geom->visibility_dependencies_depth = 0; - if (instance->scenario && instance->visibility_index != -1) { - instance->scenario->instance_visibility.move(instance->visibility_index, geom->visibility_dependencies_depth); - } - } - } + return cycle_detected; } void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_instance) { @@ -1277,7 +1313,7 @@ void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_ins bool needs_visibility_cull = has_visibility_range && is_geometry_instance && p_instance->array_index != -1; if (!needs_visibility_cull && p_instance->visibility_index != -1) { - p_instance->scenario->instance_visibility.remove(p_instance->visibility_index); + p_instance->scenario->instance_visibility.remove_at(p_instance->visibility_index); p_instance->visibility_index = -1; } else if (needs_visibility_cull && p_instance->visibility_index == -1) { InstanceVisibilityData vd; @@ -1286,33 +1322,50 @@ void RendererSceneCull::_update_instance_visibility_dependencies(Instance *p_ins vd.range_end = p_instance->visibility_range_end; vd.range_begin_margin = p_instance->visibility_range_begin_margin; vd.range_end_margin = p_instance->visibility_range_end_margin; - vd.position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f; + vd.position = p_instance->transformed_aabb.get_center(); vd.array_index = p_instance->array_index; + vd.fade_mode = p_instance->visibility_range_fade_mode; - InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data); - p_instance->scenario->instance_visibility.insert(vd, geom_data->visibility_dependencies_depth); + p_instance->scenario->instance_visibility.insert(vd, p_instance->visibility_dependencies_depth); } if (p_instance->scenario && p_instance->array_index != -1) { - p_instance->scenario->instance_data[p_instance->array_index].visibility_index = p_instance->visibility_index; + InstanceData &idata = p_instance->scenario->instance_data[p_instance->array_index]; + idata.visibility_index = p_instance->visibility_index; + + if (is_geometry_instance) { + if (has_visibility_range && p_instance->visibility_range_fade_mode == RS::VISIBILITY_RANGE_FADE_SELF) { + bool begin_enabled = p_instance->visibility_range_begin > 0.0f; + float begin_min = p_instance->visibility_range_begin - p_instance->visibility_range_begin_margin; + float begin_max = p_instance->visibility_range_begin + p_instance->visibility_range_begin_margin; + bool end_enabled = p_instance->visibility_range_end > 0.0f; + float end_min = p_instance->visibility_range_end - p_instance->visibility_range_end_margin; + float end_max = p_instance->visibility_range_end + p_instance->visibility_range_end_margin; + scene_render->geometry_instance_set_fade_range(idata.instance_geometry, begin_enabled, begin_min, begin_max, end_enabled, end_min, end_max); + } else { + scene_render->geometry_instance_set_fade_range(idata.instance_geometry, false, 0.0f, 0.0f, false, 0.0f, 0.0f); + } + } - InstanceGeometryData *geom_data = static_cast<InstanceGeometryData *>(p_instance->base_data); - if ((has_visibility_range || p_instance->visibility_parent) && (p_instance->visibility_index == -1 || (geom_data && geom_data->visibility_dependencies_depth == 0))) { - p_instance->scenario->instance_data[p_instance->array_index].flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK; + if ((has_visibility_range || p_instance->visibility_parent) && (p_instance->visibility_index == -1 || p_instance->visibility_dependencies_depth == 0)) { + idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK; } else { - p_instance->scenario->instance_data[p_instance->array_index].flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK; + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK; } if (p_instance->visibility_parent) { - p_instance->scenario->instance_data[p_instance->array_index].parent_array_index = p_instance->visibility_parent->array_index; + idata.parent_array_index = p_instance->visibility_parent->array_index; } else { - p_instance->scenario->instance_data[p_instance->array_index].parent_array_index = -1; + idata.parent_array_index = -1; + if (is_geometry_instance) { + scene_render->geometry_instance_set_parent_fade_alpha(idata.instance_geometry, 1.0f); + } } } } void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); if (instance->lightmap) { @@ -1321,7 +1374,7 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig instance->lightmap = nullptr; } - Instance *lightmap_instance = instance_owner.getornull(p_lightmap); + Instance *lightmap_instance = instance_owner.get_or_null(p_lightmap); instance->lightmap = lightmap_instance; instance->lightmap_uv_scale = p_lightmap_uv_scale; @@ -1342,7 +1395,7 @@ void RendererSceneCull::instance_geometry_set_lightmap(RID p_instance, RID p_lig } void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); instance->lod_bias = p_lod_bias; @@ -1354,7 +1407,7 @@ void RendererSceneCull::instance_geometry_set_lod_bias(RID p_instance, float p_l } void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, const StringName &p_parameter, const Variant &p_value) { - Instance *instance = instance_owner.getornull(p_instance); + Instance *instance = instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); ERR_FAIL_COND(p_value.get_type() == Variant::OBJECT); @@ -1377,7 +1430,7 @@ void RendererSceneCull::instance_geometry_set_shader_parameter(RID p_instance, c } Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance, const StringName &p_parameter) const { - const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!instance, Variant()); if (instance->instance_shader_parameters.has(p_parameter)) { @@ -1387,7 +1440,7 @@ Variant RendererSceneCull::instance_geometry_get_shader_parameter(RID p_instance } Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value(RID p_instance, const StringName &p_parameter) const { - const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance); ERR_FAIL_COND_V(!instance, Variant()); if (instance->instance_shader_parameters.has(p_parameter)) { @@ -1397,14 +1450,14 @@ Variant RendererSceneCull::instance_geometry_get_shader_parameter_default_value( } void RendererSceneCull::instance_geometry_get_shader_parameter_list(RID p_instance, List<PropertyInfo> *p_parameters) const { - const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.getornull(p_instance); + const Instance *instance = const_cast<RendererSceneCull *>(this)->instance_owner.get_or_null(p_instance); ERR_FAIL_COND(!instance); const_cast<RendererSceneCull *>(this)->update_dirty_instances(); Vector<StringName> names; - for (Map<StringName, Instance::InstanceShaderParameter>::Element *E = instance->instance_shader_parameters.front(); E; E = E->next()) { - names.push_back(E->key()); + for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : instance->instance_shader_parameters) { + names.push_back(E.key); } names.sort_custom<StringName::AlphCompare>(); for (int i = 0; i < names.size(); i++) { @@ -1471,6 +1524,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { heightfield_particle_colliders_update_list.insert(p_instance); } RSG::storage->particles_collision_instance_set_transform(collision->instance, p_instance->transform); + } else if (p_instance->base_type == RS::INSTANCE_FOG_VOLUME) { + InstanceFogVolumeData *volume = static_cast<InstanceFogVolumeData *>(p_instance->base_data); + scene_render->fog_volume_instance_set_transform(volume->instance, p_instance->transform); } else if (p_instance->base_type == RS::INSTANCE_OCCLUDER) { if (p_instance->scenario) { RendererSceneOcclusionCull::get_singleton()->scenario_set_instance(p_instance->scenario->self, p_instance->self, p_instance->base, p_instance->transform, p_instance->visible); @@ -1559,19 +1615,19 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1; idata.visibility_index = p_instance->visibility_index; + for (Set<Instance *>::Element *E = p_instance->visibility_dependencies.front(); E; E = E->next()) { + Instance *dep_instance = E->get(); + if (dep_instance->array_index != -1) { + dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = p_instance->array_index; + } + } + switch (p_instance->base_type) { case RS::INSTANCE_MESH: case RS::INSTANCE_MULTIMESH: case RS::INSTANCE_PARTICLES: { InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(p_instance->base_data); idata.instance_geometry = geom->geometry_instance; - - for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) { - Instance *dep_instance = E->get(); - if (dep_instance->array_index != -1) { - dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = p_instance->array_index; - } - } } break; case RS::INSTANCE_LIGHT: { InstanceLightData *light_data = static_cast<InstanceLightData *>(p_instance->base_data); @@ -1592,6 +1648,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { case RS::INSTANCE_VOXEL_GI: { idata.instance_data_rid = static_cast<InstanceVoxelGIData *>(p_instance->base_data)->probe_instance.get_id(); } break; + case RS::INSTANCE_FOG_VOLUME: { + idata.instance_data_rid = static_cast<InstanceFogVolumeData *>(p_instance->base_data)->instance.get_id(); + } break; case RS::INSTANCE_VISIBLITY_NOTIFIER: { idata.visibility_notifier = static_cast<InstanceVisibilityNotifierData *>(p_instance->base_data); } break; @@ -1603,7 +1662,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { //always dirty when added idata.flags |= InstanceData::FLAG_REFLECTION_PROBE_DIRTY; } - if (p_instance->cast_shadows != RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { + if (p_instance->cast_shadows != RS::SHADOW_CASTING_SETTING_OFF) { idata.flags |= InstanceData::FLAG_CAST_SHADOWS; } if (p_instance->cast_shadows == RS::SHADOW_CASTING_SETTING_SHADOWS_ONLY) { @@ -1622,6 +1681,9 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { if (p_instance->ignore_occlusion_culling) { idata.flags |= InstanceData::FLAG_IGNORE_OCCLUSION_CULLING; } + if (p_instance->ignore_all_culling) { + idata.flags |= InstanceData::FLAG_IGNORE_ALL_CULLING; + } p_instance->scenario->instance_data.push_back(idata); p_instance->scenario->instance_aabbs.push_back(InstanceBounds(p_instance->transformed_aabb)); @@ -1636,7 +1698,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { } if (p_instance->visibility_index != -1) { - p_instance->scenario->instance_visibility[p_instance->visibility_index].position = p_instance->transformed_aabb.get_position() + p_instance->transformed_aabb.get_size() / 2.0f; + p_instance->scenario->instance_visibility[p_instance->visibility_index].position = p_instance->transformed_aabb.get_center(); } //move instance and repair @@ -1721,13 +1783,10 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { swapped_instance->scenario->instance_visibility[swapped_instance->visibility_index].array_index = swapped_instance->array_index; } - if ((1 << swapped_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { - InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(swapped_instance->base_data); - for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) { - Instance *dep_instance = E->get(); - if (dep_instance != p_instance && dep_instance->array_index != -1) { - dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = swapped_instance->array_index; - } + for (Set<Instance *>::Element *E = swapped_instance->visibility_dependencies.front(); E; E = E->next()) { + Instance *dep_instance = E->get(); + if (dep_instance != p_instance && dep_instance->array_index != -1) { + dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = swapped_instance->array_index; } } } @@ -1746,11 +1805,14 @@ void RendererSceneCull::_unpair_instance(Instance *p_instance) { scene_render->geometry_instance_pair_reflection_probe_instances(geom->geometry_instance, nullptr, 0); scene_render->geometry_instance_pair_decal_instances(geom->geometry_instance, nullptr, 0); scene_render->geometry_instance_pair_voxel_gi_instances(geom->geometry_instance, nullptr, 0); + } - for (Set<Instance *>::Element *E = geom->visibility_dependencies.front(); E; E = E->next()) { - Instance *dep_instance = E->get(); - if (dep_instance->array_index != -1) { - dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = -1; + for (Set<Instance *>::Element *E = p_instance->visibility_dependencies.front(); E; E = E->next()) { + Instance *dep_instance = E->get(); + if (dep_instance->array_index != -1) { + dep_instance->scenario->instance_data[dep_instance->array_index].parent_array_index = -1; + if ((1 << dep_instance->base_type) & RS::INSTANCE_GEOMETRY_MASK) { + scene_render->geometry_instance_set_parent_fade_alpha(dep_instance->scenario->instance_data[dep_instance->array_index].instance_geometry, 1.0f); } } } @@ -1796,6 +1858,9 @@ void RendererSceneCull::_update_instance_aabb(Instance *p_instance) { new_aabb = RSG::storage->particles_collision_get_aabb(p_instance->base); } break; + case RenderingServer::INSTANCE_FOG_VOLUME: { + new_aabb = RSG::storage->fog_volume_get_aabb(p_instance->base); + } break; case RenderingServer::INSTANCE_VISIBLITY_NOTIFIER: { new_aabb = RSG::storage->visibility_notifier_get_aabb(p_instance->base); } break; @@ -1851,7 +1916,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) } Transform3D to_bounds = lightmap->transform.affine_inverse(); - Vector3 center = p_instance->transform.xform(p_instance->aabb.position + p_instance->aabb.size * 0.5); //use aabb center + Vector3 center = p_instance->transform.xform(p_instance->aabb.get_center()); //use aabb center Vector3 lm_pos = to_bounds.xform(center); @@ -2076,7 +2141,7 @@ void RendererSceneCull::_light_instance_setup_directional_shadow(int p_shadow_in // This trick here is what stabilizes the shadow (make potential jaggies to not move) // at the cost of some wasted resolution. Still, the quality increase is very well worth it. - const real_t unit = radius * 2.0 / texture_size; + const real_t unit = (radius + soft_shadow_expand) * 2.0 / texture_size; x_max_cam = Math::snapped(x_vec.dot(center) + radius + soft_shadow_expand, unit); x_min_cam = Math::snapped(x_vec.dot(center) - radius - soft_shadow_expand, unit); y_max_cam = Math::snapped(y_vec.dot(center) + radius + soft_shadow_expand, unit); @@ -2354,7 +2419,7 @@ bool RendererSceneCull::_light_instance_update_shadow(Instance *p_instance, cons void RendererSceneCull::render_camera(RID p_render_buffers, RID p_camera, RID p_scenario, RID p_viewport, Size2 p_viewport_size, float p_screen_lod_threshold, RID p_shadow_atlas, Ref<XRInterface> &p_xr_interface, RenderInfo *r_render_info) { #ifndef _3D_DISABLED - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); ERR_FAIL_COND(!camera); RendererSceneRender::CameraData camera_data; @@ -2453,34 +2518,49 @@ void RendererSceneCull::_visibility_cull(const VisibilityCullData &cull_data, ui if (idata.parent_array_index >= 0) { uint32_t parent_flags = scenario->instance_data[idata.parent_array_index].flags; - if ((parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN) || (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE) == 0) { + + if ((parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN) || !(parent_flags & (InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE | InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN))) { idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN; idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE; + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN; continue; } } - int range_check = _visibility_range_check(vd, cull_data.camera_position, cull_data.viewport_mask); + int range_check = _visibility_range_check<true>(vd, cull_data.camera_position, cull_data.viewport_mask); if (range_check == -1) { idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN; idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE; + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN; } else if (range_check == 1) { idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN; idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE; + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN; } else { idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN; idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE; + if (range_check == 2) { + idata.flags |= InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN; + } else { + idata.flags &= ~InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN; + } } } } +template <bool p_fade_check> int RendererSceneCull::_visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask) { float dist = p_camera_pos.distance_to(r_vis_data.position); + const RS::VisibilityRangeFadeMode &fade_mode = r_vis_data.fade_mode; - bool in_range_last_frame = p_viewport_mask & r_vis_data.viewport_state; - float begin_offset = in_range_last_frame ? -r_vis_data.range_begin_margin : r_vis_data.range_begin_margin; - float end_offset = in_range_last_frame ? r_vis_data.range_end_margin : -r_vis_data.range_end_margin; + float begin_offset = -r_vis_data.range_begin_margin; + float end_offset = r_vis_data.range_end_margin; + + if (fade_mode == RS::VISIBILITY_RANGE_FADE_DISABLED && !(p_viewport_mask & r_vis_data.viewport_state)) { + begin_offset = -begin_offset; + end_offset = -end_offset; + } if (r_vis_data.range_end > 0.0f && dist > r_vis_data.range_end + end_offset) { r_vis_data.viewport_state &= ~p_viewport_mask; @@ -2490,10 +2570,34 @@ int RendererSceneCull::_visibility_range_check(InstanceVisibilityData &r_vis_dat return 1; } else { r_vis_data.viewport_state |= p_viewport_mask; + if (p_fade_check) { + if (fade_mode != RS::VISIBILITY_RANGE_FADE_DISABLED) { + r_vis_data.children_fade_alpha = 1.0f; + if (r_vis_data.range_end > 0.0f && dist > r_vis_data.range_end - end_offset) { + if (fade_mode == RS::VISIBILITY_RANGE_FADE_DEPENDENCIES) { + r_vis_data.children_fade_alpha = MIN(1.0f, (dist - (r_vis_data.range_end - end_offset)) / (2.0f * r_vis_data.range_end_margin)); + } + return 2; + } else if (r_vis_data.range_begin > 0.0f && dist < r_vis_data.range_begin - begin_offset) { + if (fade_mode == RS::VISIBILITY_RANGE_FADE_DEPENDENCIES) { + r_vis_data.children_fade_alpha = MIN(1.0f, 1.0 - (dist - (r_vis_data.range_begin + begin_offset)) / (2.0f * r_vis_data.range_begin_margin)); + } + return 2; + } + } + } return 0; } } +bool RendererSceneCull::_visibility_parent_check(const CullData &p_cull_data, const InstanceData &p_instance_data) { + if (p_instance_data.parent_array_index == -1) { + return true; + } + const uint32_t &parent_flags = p_cull_data.scenario->instance_data[p_instance_data.parent_array_index].flags; + return ((parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK) == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE) || (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN); +} + void RendererSceneCull::_scene_cull_threaded(uint32_t p_thread, CullData *cull_data) { uint32_t cull_total = cull_data->scenario->instance_data.size(); uint32_t total_threads = RendererThreadPool::singleton->thread_work_pool.get_thread_count(); @@ -2519,19 +2623,19 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul bool mesh_visible = false; InstanceData &idata = cull_data.scenario->instance_data[i]; - uint32_t visibility_flags = idata.flags & (InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE | InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN); + uint32_t visibility_flags = idata.flags & (InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE | InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN | InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN); int32_t visibility_check = -1; #define HIDDEN_BY_VISIBILITY_CHECKS (visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE || visibility_flags == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN) #define LAYER_CHECK (cull_data.visible_layers & idata.layer_mask) #define IN_FRUSTUM(f) (cull_data.scenario->instance_aabbs[i].in_frustum(f)) -#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0) -#define VIS_PARENT_CHECK ((idata.parent_array_index == -1) || ((cull_data.scenario->instance_data[idata.parent_array_index].flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK) == InstanceData::FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE)) +#define VIS_RANGE_CHECK ((idata.visibility_index == -1) || _visibility_range_check<false>(cull_data.scenario->instance_visibility[idata.visibility_index], cull_data.cam_transform.origin, cull_data.visibility_viewport_mask) == 0) +#define VIS_PARENT_CHECK (_visibility_parent_check(cull_data, idata)) #define VIS_CHECK (visibility_check < 0 ? (visibility_check = (visibility_flags != InstanceData::FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK || (VIS_RANGE_CHECK && VIS_PARENT_CHECK))) : visibility_check) #define OCCLUSION_CULLED (cull_data.occlusion_buffer != nullptr && (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_OCCLUSION_CULLING) == 0 && cull_data.occlusion_buffer->is_occluded(cull_data.scenario->instance_aabbs[i].bounds, cull_data.cam_transform.origin, inv_cam_transform, *cull_data.camera_matrix, z_near)) if (!HIDDEN_BY_VISIBILITY_CHECKS) { - if (LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) { + if ((LAYER_CHECK && IN_FRUSTUM(cull_data.cull->frustum) && VIS_CHECK && !OCCLUSION_CULLED) || (cull_data.scenario->instance_data[i].flags & InstanceData::FLAG_IGNORE_ALL_CULLING)) { uint32_t base_type = idata.flags & InstanceData::FLAG_BASE_TYPE_MASK; if (base_type == RS::INSTANCE_LIGHT) { cull_result.lights.push_back(idata.instance); @@ -2574,6 +2678,8 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } else if (base_type == RS::INSTANCE_LIGHTMAP) { cull_result.lightmaps.push_back(RID::from_uint64(idata.instance_data_rid)); + } else if (base_type == RS::INSTANCE_FOG_VOLUME) { + cull_result.fog_volumes.push_back(RID::from_uint64(idata.instance_data_rid)); } else if (base_type == RS::INSTANCE_VISIBLITY_NOTIFIER) { InstanceVisibilityNotifierData *vnd = idata.visibility_notifier; if (!vnd->list_element.in_list()) { @@ -2607,6 +2713,16 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } } + if (idata.parent_array_index != -1) { + float fade = 1.0f; + const uint32_t &parent_flags = cull_data.scenario->instance_data[idata.parent_array_index].flags; + if (parent_flags & InstanceData::FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN) { + const int32_t &parent_idx = cull_data.scenario->instance_data[idata.parent_array_index].visibility_index; + fade = cull_data.scenario->instance_visibility[parent_idx].children_fade_alpha; + } + scene_render->geometry_instance_set_parent_fade_alpha(idata.instance_geometry, fade); + } + if (geometry_instance_pair_mask & (1 << RS::INSTANCE_LIGHT) && (idata.flags & InstanceData::FLAG_GEOM_LIGHTING_DIRTY)) { InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data); uint32_t idx = 0; @@ -2747,9 +2863,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul } void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows, RendererScene::RenderInfo *r_render_info) { - Instance *render_reflection_probe = instance_owner.getornull(p_reflection_probe); //if null, not rendering to it + Instance *render_reflection_probe = instance_owner.get_or_null(p_reflection_probe); //if null, not rendering to it - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); render_pass++; @@ -2952,7 +3068,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c Transform3D cam_xf = p_camera_data->main_transform; float zn = p_camera_data->main_projection.get_z_near(); - Plane p(cam_xf.origin + cam_xf.basis.get_axis(2) * -zn, -cam_xf.basis.get_axis(2)); //camera near plane + Plane p(-cam_xf.basis.get_axis(2), cam_xf.origin + cam_xf.basis.get_axis(2) * -zn); //camera near plane // near plane half width and height Vector2 vp_half_extents = p_camera_data->main_projection.get_viewport_half_extents(); @@ -3088,7 +3204,7 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c } RENDER_TIMESTAMP("Render Scene "); - scene_render->render_scene(p_render_buffers, p_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info); + scene_render->render_scene(p_render_buffers, p_camera_data, scene_cull_result.geometry_instances, scene_cull_result.light_instances, scene_cull_result.reflections, scene_cull_result.voxel_gi_instances, scene_cull_result.decals, scene_cull_result.lightmaps, scene_cull_result.fog_volumes, p_environment, camera_effects, p_shadow_atlas, occluders_tex, p_reflection_probe.is_valid() ? RID() : scenario->reflection_atlas, p_reflection_probe, p_reflection_probe_pass, p_screen_lod_threshold, render_shadow_data, max_shadows_used, render_sdfgi_data, cull.sdfgi.region_count, &sdfgi_update_data, r_render_info); for (uint32_t i = 0; i < max_shadows_used; i++) { render_shadow_data[i].instances.clear(); @@ -3103,12 +3219,12 @@ void RendererSceneCull::_render_scene(const RendererSceneRender::CameraData *p_c } RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) { - Camera *camera = camera_owner.getornull(p_camera); + Camera *camera = camera_owner.get_or_null(p_camera); if (camera && scene_render->is_environment(camera->env)) { return camera->env; } - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); if (!scenario) { return RID(); } @@ -3125,7 +3241,7 @@ RID RendererSceneCull::_render_get_environment(RID p_camera, RID p_scenario) { void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RID p_shadow_atlas) { #ifndef _3D_DISABLED - Scenario *scenario = scenario_owner.getornull(p_scenario); + Scenario *scenario = scenario_owner.get_or_null(p_scenario); RID environment; if (scenario->environment.is_valid()) { @@ -3138,7 +3254,7 @@ void RendererSceneCull::render_empty_scene(RID p_render_buffers, RID p_scenario, RendererSceneRender::CameraData camera_data; camera_data.set_camera(Transform3D(), CameraMatrix(), true, false); - scene_render->render_scene(p_render_buffers, &camera_data, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); + scene_render->render_scene(p_render_buffers, &camera_data, PagedArray<RendererSceneRender::GeometryInstance *>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), PagedArray<RID>(), RID(), RID(), p_shadow_atlas, RID(), scenario->reflection_atlas, RID(), 0, 0, nullptr, 0, nullptr, 0, nullptr); #endif } @@ -3688,9 +3804,9 @@ void RendererSceneCull::_update_dirty_instance(Instance *p_instance) { p_instance->instance_allocated_shader_parameters_offset = RSG::storage->global_variables_instance_allocate(p_instance->self); scene_render->geometry_instance_set_instance_shader_parameters_offset(geom->geometry_instance, p_instance->instance_allocated_shader_parameters_offset); - for (Map<StringName, Instance::InstanceShaderParameter>::Element *E = p_instance->instance_shader_parameters.front(); E; E = E->next()) { - if (E->get().value.get_type() != Variant::NIL) { - RSG::storage->global_variables_instance_update(p_instance->self, E->get().index, E->get().value); + for (const KeyValue<StringName, Instance::InstanceShaderParameter> &E : p_instance->instance_shader_parameters) { + if (E.value.value.get_type() != Variant::NIL) { + RSG::storage->global_variables_instance_update(p_instance->self, E.value.index, E.value.value); } } } else { @@ -3742,6 +3858,10 @@ void RendererSceneCull::update() { } bool RendererSceneCull::free(RID p_rid) { + if (p_rid.is_null()) { + return true; + } + if (scene_render->free(p_rid)) { return true; } @@ -3750,7 +3870,7 @@ bool RendererSceneCull::free(RID p_rid) { camera_owner.free(p_rid); } else if (scenario_owner.owns(p_rid)) { - Scenario *scenario = scenario_owner.getornull(p_rid); + Scenario *scenario = scenario_owner.get_or_null(p_rid); while (scenario->instances.first()) { instance_set_scenario(scenario->instances.first()->self()->self, RID()); @@ -3771,7 +3891,7 @@ bool RendererSceneCull::free(RID p_rid) { update_dirty_instances(); - Instance *instance = instance_owner.getornull(p_rid); + Instance *instance = instance_owner.get_or_null(p_rid); instance_geometry_set_lightmap(p_rid, RID(), Rect2(), 0); instance_set_scenario(p_rid, RID()); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 96fe6ce25c..e51a1fc02e 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -267,7 +267,9 @@ public: FLAG_VISIBILITY_DEPENDENCY_NEEDS_CHECK = (3 << 20), // 2 bits, overlaps with the other vis. dependency flags FLAG_VISIBILITY_DEPENDENCY_HIDDEN_CLOSE_RANGE = (1 << 20), FLAG_VISIBILITY_DEPENDENCY_HIDDEN = (1 << 21), - FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY = (1 << 22), + FLAG_VISIBILITY_DEPENDENCY_FADE_CHILDREN = (1 << 22), + FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY = (1 << 23), + FLAG_IGNORE_ALL_CULLING = (1 << 24), }; uint32_t flags = 0; @@ -286,12 +288,14 @@ public: struct InstanceVisibilityData { uint64_t viewport_state = 0; int32_t array_index = -1; + RS::VisibilityRangeFadeMode fade_mode = RS::VISIBILITY_RANGE_FADE_DISABLED; Vector3 position; Instance *instance = nullptr; float range_begin = 0.0f; float range_end = 0.0f; float range_begin_margin = 0.0f; float range_end_margin = 0.0f; + float children_fade_alpha = 1.0f; }; class VisibilityArray : public BinSortedArray<InstanceVisibilityData> { @@ -394,6 +398,7 @@ public: float lod_bias; bool ignore_occlusion_culling; + bool ignore_all_culling; Vector<RID> materials; @@ -434,14 +439,18 @@ public: RID self; //scenario stuff DynamicBVH::ID indexer_id; - int32_t array_index; + int32_t array_index = -1; int32_t visibility_index = -1; - float visibility_range_begin; - float visibility_range_end; - float visibility_range_begin_margin; - float visibility_range_end_margin; + float visibility_range_begin = 0.0f; + float visibility_range_end = 0.0f; + float visibility_range_begin_margin = 0.0f; + float visibility_range_end_margin = 0.0f; + RS::VisibilityRangeFadeMode visibility_range_fade_mode = RS::VISIBILITY_RANGE_FADE_DISABLED; Instance *visibility_parent = nullptr; - Scenario *scenario; + Set<Instance *> visibility_dependencies; + uint32_t visibility_dependencies_depth = 0; + float transparency = 0.0f; + Scenario *scenario = nullptr; SelfList<Instance> scenario_item; //aabb stuff @@ -529,6 +538,7 @@ public: lightmap_cull_index = 0; lod_bias = 1.0; ignore_occlusion_culling = false; + ignore_all_culling = false; scenario = nullptr; @@ -583,8 +593,6 @@ public: Set<Instance *> reflection_probes; Set<Instance *> voxel_gi_instances; Set<Instance *> lightmap_captures; - Set<Instance *> visibility_dependencies; - uint32_t visibility_dependencies_depth = 0; InstanceGeometryData() { can_cast_shadows = true; @@ -624,6 +632,11 @@ public: RID instance; }; + struct InstanceFogVolumeData : public InstanceBaseData { + RID instance; + bool is_global; + }; + struct InstanceVisibilityNotifierData : public InstanceBaseData { bool just_visible = false; uint64_t visible_in_frame = 0; @@ -788,6 +801,7 @@ public: PagedArray<RID> decals; PagedArray<RID> voxel_gi_instances; PagedArray<RID> mesh_instances; + PagedArray<RID> fog_volumes; struct DirectionalShadow { PagedArray<RendererSceneRender::GeometryInstance *> cascade_geometry_instances[RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES]; @@ -805,6 +819,7 @@ public: decals.clear(); voxel_gi_instances.clear(); mesh_instances.clear(); + fog_volumes.clear(); for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { directional_shadows[i].cascade_geometry_instances[j].clear(); @@ -829,6 +844,7 @@ public: decals.reset(); voxel_gi_instances.reset(); mesh_instances.reset(); + fog_volumes.reset(); for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { directional_shadows[i].cascade_geometry_instances[j].reset(); @@ -853,6 +869,7 @@ public: decals.merge_unordered(p_cull_result.decals); voxel_gi_instances.merge_unordered(p_cull_result.voxel_gi_instances); mesh_instances.merge_unordered(p_cull_result.mesh_instances); + fog_volumes.merge_unordered(p_cull_result.fog_volumes); for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { @@ -878,6 +895,7 @@ public: decals.set_page_pool(p_rid_pool); voxel_gi_instances.set_page_pool(p_rid_pool); mesh_instances.set_page_pool(p_rid_pool); + fog_volumes.set_page_pool(p_rid_pool); for (int i = 0; i < RendererSceneRender::MAX_DIRECTIONAL_LIGHTS; i++) { for (int j = 0; j < RendererSceneRender::MAX_DIRECTIONAL_LIGHT_CASCADES; j++) { directional_shadows[i].cascade_geometry_instances[j].set_page_pool(p_geometry_instance_pool); @@ -920,6 +938,7 @@ public: virtual void instance_set_blend_shape_weight(RID p_instance, int p_shape, float p_weight); virtual void instance_set_surface_override_material(RID p_instance, int p_surface, RID p_material); virtual void instance_set_visible(RID p_instance, bool p_visible); + virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency); virtual void instance_set_custom_aabb(RID p_instance, AABB p_aabb); @@ -929,7 +948,9 @@ public: virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance); - void _update_instance_visibility_depth(Instance *p_instance); + virtual void instance_set_ignore_culling(RID p_instance, bool p_enabled); + + bool _update_instance_visibility_depth(Instance *p_instance); void _update_instance_visibility_dependencies(Instance *p_instance); // don't use these in a game! @@ -941,7 +962,7 @@ public: virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, RS::ShadowCastingSetting p_shadow_casting_setting); virtual void instance_geometry_set_material_override(RID p_instance, RID p_material); - virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin); + virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, RS::VisibilityRangeFadeMode p_fade_mode); virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_slice_index); virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias); @@ -1013,7 +1034,7 @@ public: void _visibility_cull_threaded(uint32_t p_thread, VisibilityCullData *cull_data); void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_from, uint64_t p_to); - _FORCE_INLINE_ void _visibility_cull(const VisibilityCullData &cull_data, uint64_t p_idx); + template <bool p_fade_check> _FORCE_INLINE_ int _visibility_range_check(InstanceVisibilityData &r_vis_data, const Vector3 &p_camera_pos, uint64_t p_viewport_mask); struct CullData { @@ -1030,6 +1051,7 @@ public: void _scene_cull_threaded(uint32_t p_thread, CullData *cull_data); void _scene_cull(CullData &cull_data, InstanceCullResult &cull_result, uint64_t p_from, uint64_t p_to); + _FORCE_INLINE_ bool _visibility_parent_check(const CullData &p_cull_data, const InstanceData &p_instance_data); bool _render_reflection_probe_step(Instance *p_instance, int p_step); void _render_scene(const RendererSceneRender::CameraData *p_camera_data, RID p_render_buffers, RID p_environment, RID p_force_camera_effects, uint32_t p_visible_layers, RID p_scenario, RID p_viewport, RID p_shadow_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, bool p_using_shadows = true, RenderInfo *r_render_info = nullptr); @@ -1078,7 +1100,7 @@ public: PASS2(environment_set_bg_color, RID, const Color &) PASS2(environment_set_bg_energy, RID, float) PASS2(environment_set_canvas_max_layer, RID, int) - PASS7(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource, const Color &) + PASS6(environment_set_ambient_light, RID, const Color &, RS::EnvironmentAmbientSource, float, float, RS::EnvironmentReflectionSource) PASS6(environment_set_ssr, RID, bool, int, float, float, float) PASS1(environment_set_ssr_roughness_quality, RS::EnvironmentSSRRoughnessQuality) @@ -1095,7 +1117,7 @@ public: PASS7(environment_set_adjustment, RID, bool, float, float, float, bool, RID) PASS9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float) - PASS10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float) + PASS13(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float) PASS2(environment_set_volumetric_fog_volume_size, int, int) PASS1(environment_set_volumetric_fog_filter_active, bool) @@ -1133,7 +1155,7 @@ public: /* Render Buffers */ PASS0R(RID, render_buffers_create) - PASS8(render_buffers_configure, RID, RID, int, int, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t) + PASS12(render_buffers_configure, RID, RID, int, int, int, int, float, float, RS::ViewportMSAA, RS::ViewportScreenSpaceAA, bool, uint32_t) PASS1(gi_set_use_half_resolution, bool) /* Shadow Atlas */ @@ -1158,4 +1180,4 @@ public: virtual ~RendererSceneCull(); }; -#endif // VISUALSERVERSCENE_H +#endif // RENDERING_SERVER_SCENE_CULL_H diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index e06b3ba153..4e4b1b94db 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -76,26 +76,28 @@ public: return false; } - float min_depth; - if (p_cam_projection.is_orthogonal()) { - min_depth = (-closest_point_view.z) - p_near; - } else { - float r = -p_near / closest_point_view.z; - Vector3 closest_point_proj = Vector3(closest_point_view.x * r, closest_point_view.y * r, -p_near); - min_depth = closest_point_proj.distance_to(closest_point_view); - } + float min_depth = -closest_point_view.z * 0.95f; Vector2 rect_min = Vector2(FLT_MAX, FLT_MAX); Vector2 rect_max = Vector2(FLT_MIN, FLT_MIN); for (int j = 0; j < 8; j++) { - Vector3 c = RendererSceneOcclusionCull::HZBuffer::corners[j]; + const Vector3 &c = RendererSceneOcclusionCull::HZBuffer::corners[j]; Vector3 nc = Vector3(1, 1, 1) - c; Vector3 corner = Vector3(p_bounds[0] * c.x + p_bounds[3] * nc.x, p_bounds[1] * c.y + p_bounds[4] * nc.y, p_bounds[2] * c.z + p_bounds[5] * nc.z); Vector3 view = p_cam_inv_transform.xform(corner); - Vector3 projected = p_cam_projection.xform(view); - Vector2 normalized = Vector2(projected.x * 0.5f + 0.5f, projected.y * 0.5f + 0.5f); + Plane vp = Plane(view, 1.0); + Plane projected = p_cam_projection.xform4(vp); + + float w = projected.d; + if (w < 1.0) { + rect_min = Vector2(0.0f, 0.0f); + rect_max = Vector2(1.0f, 1.0f); + break; + } + + Vector2 normalized = Vector2(projected.normal.x / w * 0.5f + 0.5f, projected.normal.y / w * 0.5f + 0.5f); rect_min = rect_min.min(normalized); rect_max = rect_max.max(normalized); } diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp index 3a230ac89d..38d1218dee 100644 --- a/servers/rendering/renderer_scene_render.cpp +++ b/servers/rendering/renderer_scene_render.cpp @@ -68,7 +68,7 @@ void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count main_transform.basis.set(x, y, z); // 3. create a horizon plane with one of the eyes and the up vector as normal. - Plane horizon(p_transforms[0].origin, y); + Plane horizon(y, p_transforms[0].origin); // 4. Intersect horizon, left and right to obtain the combined camera origin. ERR_FAIL_COND_MSG( @@ -79,7 +79,7 @@ void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count // 5. figure out far plane, this could use some improvement, we may have our far plane too close like this, not sure if this matters Vector3 far_center = (planes[0][CameraMatrix::PLANE_FAR].center() + planes[1][CameraMatrix::PLANE_FAR].center()) * 0.5; - Plane far(far_center, -z); + Plane far(-z, far_center); ///////////////////////////////////////////////////////////////////////////// // Figure out our top/bottom planes @@ -137,9 +137,9 @@ void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count Plane near; Vector3 neg_z = -z; if (neg_z.dot(p_transforms[1].origin) < neg_z.dot(p_transforms[0].origin)) { - near = Plane(p_transforms[0].origin, neg_z); + near = Plane(neg_z, p_transforms[0].origin); } else { - near = Plane(p_transforms[1].origin, neg_z); + near = Plane(neg_z, p_transforms[1].origin); } // 13. Intersect near plane with bottm/left planes, to obtain min_vec then top/right to obtain max_vec diff --git a/servers/rendering/renderer_scene_render.h b/servers/rendering/renderer_scene_render.h index 2000afa0d3..0d71ea22da 100644 --- a/servers/rendering/renderer_scene_render.h +++ b/servers/rendering/renderer_scene_render.h @@ -56,6 +56,9 @@ public: virtual void geometry_instance_set_transform(GeometryInstance *p_geometry_instance, const Transform3D &p_transform, const AABB &p_aabb, const AABB &p_transformed_aabbb) = 0; virtual void geometry_instance_set_layer_mask(GeometryInstance *p_geometry_instance, uint32_t p_layer_mask) = 0; virtual void geometry_instance_set_lod_bias(GeometryInstance *p_geometry_instance, float p_lod_bias) = 0; + virtual void geometry_instance_set_transparency(GeometryInstance *p_geometry_instance, float p_transparency) = 0; + virtual void geometry_instance_set_fade_range(GeometryInstance *p_geometry_instance, bool p_enable_near, float p_near_begin, float p_near_end, bool p_enable_far, float p_far_begin, float p_far_end) = 0; + virtual void geometry_instance_set_parent_fade_alpha(GeometryInstance *p_geometry_instance, float p_alpha) = 0; virtual void geometry_instance_set_use_baked_light(GeometryInstance *p_geometry_instance, bool p_enable) = 0; virtual void geometry_instance_set_use_dynamic_gi(GeometryInstance *p_geometry_instance, bool p_enable) = 0; virtual void geometry_instance_set_use_lightmap(GeometryInstance *p_geometry_instance, RID p_lightmap_instance, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice_index) = 0; @@ -113,7 +116,7 @@ public: virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; - virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, RS::EnvironmentAmbientSource p_ambient = RS::ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, RS::EnvironmentReflectionSource p_reflection_source = RS::ENV_REFLECTION_SOURCE_BG) = 0; // FIXME: Disabled during Vulkan refactoring, should be ported. #if 0 virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) = 0; @@ -123,7 +126,7 @@ public: virtual void environment_glow_set_use_bicubic_upscale(bool p_enable) = 0; virtual void environment_glow_set_use_high_quality(bool p_enable) = 0; - virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0; + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0; virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; @@ -173,6 +176,12 @@ public: return true; } + virtual RID fog_volume_instance_create(RID p_fog_volume) = 0; + virtual void fog_volume_instance_set_transform(RID p_fog_volume_instance, const Transform3D &p_transform) = 0; + virtual void fog_volume_instance_set_active(RID p_fog_volume_instance, bool p_active) = 0; + virtual RID fog_volume_instance_get_volume(RID p_fog_volume_instance) const = 0; + virtual Vector3 fog_volume_instance_get_position(RID p_fog_volume_instance) const = 0; + virtual RID reflection_atlas_create() = 0; virtual void reflection_atlas_set_size(RID p_ref_atlas, int p_reflection_size, int p_reflection_count) = 0; virtual int reflection_atlas_get_size(RID p_ref_atlas) const = 0; @@ -237,7 +246,7 @@ public: void set_multiview_camera(uint32_t p_view_count, const Transform3D *p_transforms, const CameraMatrix *p_projections, bool p_is_ortogonal, bool p_vaspect); }; - virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0; + virtual void render_scene(RID p_render_buffers, const CameraData *p_camera_data, const PagedArray<GeometryInstance *> &p_instances, const PagedArray<RID> &p_lights, const PagedArray<RID> &p_reflection_probes, const PagedArray<RID> &p_voxel_gi_instances, const PagedArray<RID> &p_decals, const PagedArray<RID> &p_lightmaps, const PagedArray<RID> &p_fog_volumes, RID p_environment, RID p_camera_effects, RID p_shadow_atlas, RID p_occluder_debug_tex, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass, float p_screen_lod_threshold, const RenderShadowData *p_render_shadows, int p_render_shadow_count, const RenderSDFGIData *p_render_sdfgi_regions, int p_render_sdfgi_region_count, const RenderSDFGIUpdateData *p_sdfgi_update_data = nullptr, RendererScene::RenderInfo *r_render_info = nullptr) = 0; virtual void render_material(const Transform3D &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, const PagedArray<GeometryInstance *> &p_instances, RID p_framebuffer, const Rect2i &p_region) = 0; virtual void render_particle_collider_heightfield(RID p_collider, const Transform3D &p_transform, const PagedArray<GeometryInstance *> &p_instances) = 0; @@ -247,7 +256,7 @@ public: virtual void set_debug_draw_mode(RS::ViewportDebugDraw p_debug_draw) = 0; virtual RID render_buffers_create() = 0; - virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_width, int p_height, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; + virtual void render_buffers_configure(RID p_render_buffers, RID p_render_target, int p_internal_width, int p_internal_height, int p_width, int p_height, float p_fsr_sharpness, float p_fsr_mipmap_bias, RS::ViewportMSAA p_msaa, RS::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_debanding, uint32_t p_view_count) = 0; virtual void gi_set_use_half_resolution(bool p_enable) = 0; virtual void screen_space_roughness_limiter_set_active(bool p_enable, float p_amount, float p_limit) = 0; diff --git a/servers/rendering/renderer_storage.cpp b/servers/rendering/renderer_storage.cpp index a402ecc668..aa005fac0a 100644 --- a/servers/rendering/renderer_storage.cpp +++ b/servers/rendering/renderer_storage.cpp @@ -33,21 +33,21 @@ RendererStorage *RendererStorage::base_singleton = nullptr; void RendererStorage::Dependency::changed_notify(DependencyChangedNotification p_notification) { - for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { - if (E->key()->changed_callback) { - E->key()->changed_callback(p_notification, E->key()); + for (const KeyValue<DependencyTracker *, uint32_t> &E : instances) { + if (E.key->changed_callback) { + E.key->changed_callback(p_notification, E.key); } } } void RendererStorage::Dependency::deleted_notify(const RID &p_rid) { - for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { - if (E->key()->deleted_callback) { - E->key()->deleted_callback(p_rid, E->key()); + for (const KeyValue<DependencyTracker *, uint32_t> &E : instances) { + if (E.key->deleted_callback) { + E.key->deleted_callback(p_rid, E.key); } } - for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { - E->key()->dependencies.erase(this); + for (const KeyValue<DependencyTracker *, uint32_t> &E : instances) { + E.key->dependencies.erase(this); } instances.clear(); } @@ -56,8 +56,8 @@ RendererStorage::Dependency::~Dependency() { #ifdef DEBUG_ENABLED if (instances.size()) { WARN_PRINT("Leaked instance dependency: Bug - did not call instance_notify_deleted when freeing."); - for (Map<DependencyTracker *, uint32_t>::Element *E = instances.front(); E; E = E->next()) { - E->key()->dependencies.erase(this); + for (const KeyValue<DependencyTracker *, uint32_t> &E : instances) { + E.key->dependencies.erase(this); } } #endif diff --git a/servers/rendering/renderer_storage.h b/servers/rendering/renderer_storage.h index 2304394501..8926bf24aa 100644 --- a/servers/rendering/renderer_storage.h +++ b/servers/rendering/renderer_storage.h @@ -183,8 +183,8 @@ public: virtual String shader_get_code(RID p_shader) const = 0; virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0; - virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; - virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0; + virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index) = 0; + virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index) const = 0; virtual Variant shader_get_param_default(RID p_material, const StringName &p_param) const = 0; virtual RS::ShaderNativeSourceCode shader_get_native_source_code(RID p_shader) const = 0; @@ -535,6 +535,19 @@ public: virtual bool particles_collision_is_heightfield(RID p_particles_collision) const = 0; virtual RID particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const = 0; + /* FOG VOLUMES */ + + virtual RID fog_volume_allocate() = 0; + virtual void fog_volume_initialize(RID p_rid) = 0; + + virtual void fog_volume_set_shape(RID p_fog_volume, RS::FogVolumeShape p_shape) = 0; + virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) = 0; + virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) = 0; + virtual AABB fog_volume_get_aabb(RID p_fog_volume) const = 0; + virtual RS::FogVolumeShape fog_volume_get_shape(RID p_fog_volume) const = 0; + + /* VISIBILITY NOTIFIER */ + virtual RID visibility_notifier_allocate() = 0; virtual void visibility_notifier_initialize(RID p_notifier) = 0; virtual void visibility_notifier_set_aabb(RID p_notifier, const AABB &p_aabb) = 0; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 3ede9fed2d..8a14834569 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -77,34 +77,69 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { RSG::scene->free(p_viewport->render_buffers); p_viewport->render_buffers = RID(); } else { - RS::ViewportScale3D scale_3d = p_viewport->scale_3d; - if (Engine::get_singleton()->is_editor_hint()) { // ignore this inside of the editor - scale_3d = RS::VIEWPORT_SCALE_3D_DISABLED; + float scaling_3d_scale = p_viewport->scaling_3d_scale; + + RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode; + bool scaling_enabled = true; + + if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && (scaling_3d_scale > 1.0)) { + // FSR is not design for downsampling. + // Throw a warning and fallback to VIEWPORT_SCALING_3D_MODE_BILINEAR + print_error("FSR does not support supersampling. Falling back to bilinear mode."); + scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_BILINEAR; } - int width = p_viewport->size.width; - int height = p_viewport->size.height; - switch (scale_3d) { - case RS::VIEWPORT_SCALE_3D_75_PERCENT: { - width = (width * 3) / 4; - height = (height * 3) / 4; - }; break; - case RS::VIEWPORT_SCALE_3D_50_PERCENT: { - width = width >> 1; - height = height >> 1; - }; break; - case RS::VIEWPORT_SCALE_3D_33_PERCENT: { - width = width / 3; - height = height / 3; - }; break; - case RS::VIEWPORT_SCALE_3D_25_PERCENT: { - width = width >> 2; - height = height >> 2; - }; break; - default: - break; + if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && !p_viewport->fsr_enabled) { + // FSR is not actually available. + // Throw a warning and fallback to disable scaling + print_error("FSR is not available. Disabled FSR scaling 3D. Try bilinear mode."); + scaling_enabled = false; } - RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, width, height, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding, p_viewport->get_view_count()); + + if (scaling_3d_scale == 1.0) { + scaling_enabled = false; + } + + int width; + int height; + int render_width; + int render_height; + + if (scaling_enabled) { + switch (scaling_3d_mode) { + case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR: + // Clamp 3D rendering resolution to reasonable values supported on most hardware. + // This prevents freezing the engine or outright crashing on lower-end GPUs. + width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384); + height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384); + render_width = width; + render_height = height; + break; + case RS::VIEWPORT_SCALING_3D_MODE_FSR: + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling) + render_height = MAX(height * scaling_3d_scale, 1.0); + break; + default: + // This is an unknown mode. + print_error(vformat("Unknown scaling mode: %d, disabling scaling 3D", scaling_3d_mode)); + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = width; + render_height = height; + break; + } + } else { + width = p_viewport->size.width; + height = p_viewport->size.height; + render_width = width; + render_height = height; + } + + p_viewport->internal_size = Size2(render_width, render_height); + + RSG::scene->render_buffers_configure(p_viewport->render_buffers, p_viewport->render_target, render_width, render_height, width, height, p_viewport->fsr_sharpness, p_viewport->fsr_mipmap_bias, p_viewport->msaa, p_viewport->screen_space_aa, p_viewport->use_debanding, p_viewport->get_view_count()); } } } @@ -133,7 +168,7 @@ void RendererViewport::_draw_3d(Viewport *p_viewport) { } float screen_lod_threshold = p_viewport->lod_threshold / float(p_viewport->size.width); - RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info); + RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->internal_size, screen_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info); RENDER_TIMESTAMP("<End Rendering 3D Scene"); } @@ -145,6 +180,11 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { timestamp_vp_map[rt_id] = p_viewport->self; } + if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") { + // This is currently needed for GLES to keep the current window being rendered to up to date + DisplayServer::get_singleton()->gl_window_make_current(p_viewport->viewport_to_screen); + } + /* Camera should always be BEFORE any other 3D */ bool scenario_draw_canvas_bg = false; //draw canvas, or some layer of it, as BG for 3D instead of in front @@ -210,9 +250,9 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { RendererCanvasRender::LightOccluderInstance *occluders = nullptr; //make list of occluders - for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); - Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); + for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) { + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas); + Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size); for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { if (!F->get()->enabled) { @@ -242,10 +282,10 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { int directional_light_count = 0; RENDER_TIMESTAMP("Cull Canvas Lights"); - for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); + for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) { + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas); - Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); + Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size); //find lights in canvas @@ -307,7 +347,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { } } - canvas_map[Viewport::CanvasKey(E->key(), E->get().layer, E->get().sublayer)] = &E->get(); + canvas_map[Viewport::CanvasKey(E.key, E.value.layer, E.value.sublayer)] = &E.value; } if (lights_with_shadow) { @@ -319,9 +359,9 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { RENDER_TIMESTAMP("Cull Occluders"); //make list of occluders - for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); - Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); + for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) { + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas); + Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size); for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { if (!F->get()->enabled) { @@ -400,9 +440,9 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { //make list of occluders int occ_cullded = 0; - for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) { - RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get().canvas); - Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size); + for (KeyValue<RID, Viewport::CanvasData> &E : p_viewport->canvas_map) { + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value.canvas); + Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E.value, clip_rect.size); for (Set<RendererCanvasRender::LightOccluderInstance *>::Element *F = canvas->occluders.front(); F; F = F->next()) { if (!F->get()->enabled) { @@ -439,17 +479,17 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { scenario_draw_canvas_bg = false; } - for (Map<Viewport::CanvasKey, Viewport::CanvasData *>::Element *E = canvas_map.front(); E; E = E->next()) { - RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E->get()->canvas); + for (const KeyValue<Viewport::CanvasKey, Viewport::CanvasData *> &E : canvas_map) { + RendererCanvasCull::Canvas *canvas = static_cast<RendererCanvasCull::Canvas *>(E.value->canvas); - Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size); + Transform2D xform = _canvas_get_transform(p_viewport, canvas, E.value, clip_rect.size); RendererCanvasRender::Light *canvas_lights = nullptr; RendererCanvasRender::Light *canvas_directional_lights = nullptr; RendererCanvasRender::Light *ptr = lights; while (ptr) { - if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) { + if (E.value->layer >= ptr->layer_min && E.value->layer <= ptr->layer_max) { ptr->next_ptr = canvas_lights; canvas_lights = ptr; } @@ -458,7 +498,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { ptr = directional_lights; while (ptr) { - if (E->get()->layer >= ptr->layer_min && E->get()->layer <= ptr->layer_max) { + if (E.value->layer >= ptr->layer_min && E.value->layer <= ptr->layer_max) { ptr->next_ptr = canvas_directional_lights; canvas_directional_lights = ptr; } @@ -471,7 +511,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { } i++; - if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) { + if (scenario_draw_canvas_bg && E.key.get_layer() >= scenario_canvas_max_layer) { if (!can_draw_3d) { RSG::scene->render_empty_scene(p_viewport->render_buffers, p_viewport->scenario, p_viewport->shadow_atlas); } else { @@ -511,9 +551,6 @@ void RendererViewport::draw_viewports() { if (XRServer::get_singleton() != nullptr) { xr_interface = XRServer::get_singleton()->get_primary_interface(); - - // process all our active interfaces - XRServer::get_singleton()->_process(); } if (Engine::get_singleton()->is_editor_hint()) { @@ -554,7 +591,7 @@ void RendererViewport::draw_viewports() { } if (vp->update_mode == RS::VIEWPORT_UPDATE_WHEN_PARENT_VISIBLE) { - Viewport *parent = viewport_owner.getornull(vp->parent); + Viewport *parent = viewport_owner.get_or_null(vp->parent); if (parent && parent->last_pass == draw_viewports_pass) { visible = true; } @@ -585,7 +622,7 @@ void RendererViewport::draw_viewports() { // override our size, make sure it matches our required size and is created as a stereo target vp->size = xr_interface->get_render_target_size(); uint32_t view_count = xr_interface->get_view_count(); - RSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y, view_count); + RSG::storage->render_target_set_size(vp->render_target, vp->internal_size.x, vp->internal_size.y, view_count); // check for an external texture destination (disabled for now, not yet supported) // RSG::storage->render_target_set_external_texture(vp->render_target, xr_interface->get_external_texture_for_eye(leftOrMono)); @@ -626,10 +663,10 @@ void RendererViewport::draw_viewports() { BlitToScreen blit; blit.render_target = vp->render_target; if (vp->viewport_to_screen_rect != Rect2()) { - blit.rect = vp->viewport_to_screen_rect; + blit.dst_rect = vp->viewport_to_screen_rect; } else { - blit.rect.position = Vector2(); - blit.rect.size = vp->size; + blit.dst_rect.position = Vector2(); + blit.dst_rect.size = vp->size; } if (!blit_to_screen_list.has(vp->viewport_to_screen)) { @@ -660,8 +697,8 @@ void RendererViewport::draw_viewports() { //this needs to be called to make screen swapping more efficient RSG::rasterizer->prepare_for_blitting_render_targets(); - for (Map<int, Vector<BlitToScreen>>::Element *E = blit_to_screen_list.front(); E; E = E->next()) { - RSG::rasterizer->blit_render_targets_to_screen(E->key(), E->get().ptr(), E->get().size()); + for (const KeyValue<int, Vector<BlitToScreen>> &E : blit_to_screen_list) { + RSG::rasterizer->blit_render_targets_to_screen(E.key, E.value.ptr(), E.value.size()); } } @@ -671,15 +708,17 @@ RID RendererViewport::viewport_allocate() { void RendererViewport::viewport_initialize(RID p_rid) { viewport_owner.initialize_rid(p_rid); - Viewport *viewport = viewport_owner.getornull(p_rid); + Viewport *viewport = viewport_owner.get_or_null(p_rid); viewport->self = p_rid; viewport->render_target = RSG::storage->render_target_create(); viewport->shadow_atlas = RSG::scene->shadow_atlas_create(); viewport->viewport_render_direct_to_screen = false; + + viewport->fsr_enabled = !RSG::rasterizer->is_low_end() && !viewport->disable_3d; } void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (viewport->use_xr == p_use_xr) { @@ -690,15 +729,42 @@ void RendererViewport::viewport_set_use_xr(RID p_viewport, bool p_use_xr) { _configure_3d_render_buffers(viewport); } -void RendererViewport::viewport_set_scale_3d(RID p_viewport, RenderingServer::ViewportScale3D p_scale_3d) { - Viewport *viewport = viewport_owner.getornull(p_viewport); +void RendererViewport::viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); - if (viewport->scale_3d == p_scale_3d) { + viewport->scaling_3d_mode = p_mode; + _configure_3d_render_buffers(viewport); +} + +void RendererViewport::viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->fsr_sharpness = p_sharpness; + _configure_3d_render_buffers(viewport); +} + +void RendererViewport::viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + viewport->fsr_mipmap_bias = p_mipmap_bias; + _configure_3d_render_buffers(viewport); +} + +void RendererViewport::viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_COND(!viewport); + + // Clamp to reasonable values that are actually useful. + // Values above 2.0 don't serve a practical purpose since the viewport + // isn't displayed with mipmaps. + if (viewport->scaling_3d_scale == CLAMP(p_scaling_3d_scale, 0.1, 2.0)) { return; } - viewport->scale_3d = p_scale_3d; + viewport->scaling_3d_scale = CLAMP(p_scaling_3d_scale, 0.1, 2.0); _configure_3d_render_buffers(viewport); } @@ -720,10 +786,11 @@ uint32_t RendererViewport::Viewport::get_view_count() { void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_height) { ERR_FAIL_COND(p_width < 0 && p_height < 0); - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->size = Size2(p_width, p_height); + uint32_t view_count = viewport->get_view_count(); RSG::storage->render_target_set_size(viewport->render_target, p_width, p_height, view_count); _configure_3d_render_buffers(viewport); @@ -732,7 +799,7 @@ void RendererViewport::viewport_set_size(RID p_viewport, int p_width, int p_heig } void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (p_active) { @@ -745,25 +812,25 @@ void RendererViewport::viewport_set_active(RID p_viewport, bool p_active) { } void RendererViewport::viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->parent = p_parent_viewport; } void RendererViewport::viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->clear_mode = p_clear_mode; } void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect, DisplayServer::WindowID p_screen) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (p_screen != DisplayServer::INVALID_WINDOW_ID) { - // If using GLES2 we can optimize this operation by rendering directly to system_fbo + // If using OpenGL we can optimize this operation by rendering directly to system_fbo // instead of rendering to fbo and copying to system_fbo after if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { RSG::storage->render_target_set_size(viewport->render_target, p_rect.size.x, p_rect.size.y, viewport->get_view_count()); @@ -776,7 +843,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_ // if render_direct_to_screen was used, reset size and position if (RSG::rasterizer->is_low_end() && viewport->viewport_render_direct_to_screen) { RSG::storage->render_target_set_position(viewport->render_target, 0, 0); - RSG::storage->render_target_set_size(viewport->render_target, viewport->size.x, viewport->size.y, viewport->get_view_count()); + RSG::storage->render_target_set_size(viewport->render_target, viewport->internal_size.x, viewport->internal_size.y, viewport->get_view_count()); } viewport->viewport_to_screen_rect = Rect2(); @@ -785,7 +852,7 @@ void RendererViewport::viewport_attach_to_screen(RID p_viewport, const Rect2 &p_ } void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (p_enable == viewport->viewport_render_direct_to_screen) { @@ -809,21 +876,21 @@ void RendererViewport::viewport_set_render_direct_to_screen(RID p_viewport, bool } void RendererViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->update_mode = p_mode; } RID RendererViewport::viewport_get_texture(RID p_viewport) const { - const Viewport *viewport = viewport_owner.getornull(p_viewport); + const Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND_V(!viewport, RID()); return RSG::storage->render_target_get_texture(viewport->render_target); } RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const { - const Viewport *viewport = viewport_owner.getornull(p_viewport); + const Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND_V(!viewport, RID()); if (viewport->use_occlusion_culling && viewport->debug_draw == RenderingServer::VIEWPORT_DEBUG_DRAW_OCCLUDERS) { @@ -833,35 +900,35 @@ RID RendererViewport::viewport_get_occluder_debug_texture(RID p_viewport) const } void RendererViewport::viewport_set_disable_2d(RID p_viewport, bool p_disable) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->disable_2d = p_disable; } void RendererViewport::viewport_set_disable_environment(RID p_viewport, bool p_disable) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->disable_environment = p_disable; } void RendererViewport::viewport_set_disable_3d(RID p_viewport, bool p_disable) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->disable_3d = p_disable; } void RendererViewport::viewport_attach_camera(RID p_viewport, RID p_camera) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->camera = p_camera; } void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (viewport->scenario.is_valid()) { @@ -875,11 +942,11 @@ void RendererViewport::viewport_set_scenario(RID p_viewport, RID p_scenario) { } void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); ERR_FAIL_COND(viewport->canvas_map.has(p_canvas)); - RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); + RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.get_or_null(p_canvas); ERR_FAIL_COND(!canvas); canvas->viewports.insert(p_viewport); @@ -890,10 +957,10 @@ void RendererViewport::viewport_attach_canvas(RID p_viewport, RID p_canvas) { } void RendererViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); - RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.getornull(p_canvas); + RendererCanvasCull::Canvas *canvas = RSG::canvas->canvas_owner.get_or_null(p_canvas); ERR_FAIL_COND(!canvas); viewport->canvas_map.erase(p_canvas); @@ -901,7 +968,7 @@ void RendererViewport::viewport_remove_canvas(RID p_viewport, RID p_canvas) { } void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canvas, const Transform2D &p_offset) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas)); @@ -909,7 +976,7 @@ void RendererViewport::viewport_set_canvas_transform(RID p_viewport, RID p_canva } void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool p_enabled) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); RSG::storage->render_target_set_flag(viewport->render_target, RendererStorage::RENDER_TARGET_TRANSPARENT, p_enabled); @@ -917,14 +984,14 @@ void RendererViewport::viewport_set_transparent_background(RID p_viewport, bool } void RendererViewport::viewport_set_global_canvas_transform(RID p_viewport, const Transform2D &p_transform) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->global_transform = p_transform; } void RendererViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas, int p_layer, int p_sublayer) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); ERR_FAIL_COND(!viewport->canvas_map.has(p_canvas)); @@ -933,7 +1000,7 @@ void RendererViewport::viewport_set_canvas_stacking(RID p_viewport, RID p_canvas } void RendererViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size, bool p_16_bits) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->shadow_atlas_size = p_size; @@ -943,14 +1010,14 @@ void RendererViewport::viewport_set_shadow_atlas_size(RID p_viewport, int p_size } void RendererViewport::viewport_set_shadow_atlas_quadrant_subdivision(RID p_viewport, int p_quadrant, int p_subdiv) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); RSG::scene->shadow_atlas_set_quadrant_subdivision(viewport->shadow_atlas, p_quadrant, p_subdiv); } void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (viewport->msaa == p_msaa) { @@ -961,7 +1028,7 @@ void RendererViewport::viewport_set_msaa(RID p_viewport, RS::ViewportMSAA p_msaa } void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::ViewportScreenSpaceAA p_mode) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (viewport->screen_space_aa == p_mode) { @@ -972,7 +1039,7 @@ void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::Viewport } void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_debanding) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (viewport->use_debanding == p_use_debanding) { @@ -983,7 +1050,7 @@ void RendererViewport::viewport_set_use_debanding(RID p_viewport, bool p_use_deb } void RendererViewport::viewport_set_use_occlusion_culling(RID p_viewport, bool p_use_occlusion_culling) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); if (viewport->use_occlusion_culling == p_use_occlusion_culling) { @@ -1018,16 +1085,17 @@ void RendererViewport::viewport_set_occlusion_culling_build_quality(RS::Viewport } void RendererViewport::viewport_set_lod_threshold(RID p_viewport, float p_pixels) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->lod_threshold = p_pixels; } int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRenderInfoType p_type, RS::ViewportRenderInfo p_info) { + ERR_FAIL_INDEX_V(p_type, RS::VIEWPORT_RENDER_INFO_TYPE_MAX, -1); ERR_FAIL_INDEX_V(p_info, RS::VIEWPORT_RENDER_INFO_MAX, -1); - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); if (!viewport) { return 0; //there should be a lock here.. } @@ -1036,62 +1104,62 @@ int RendererViewport::viewport_get_render_info(RID p_viewport, RS::ViewportRende } void RendererViewport::viewport_set_debug_draw(RID p_viewport, RS::ViewportDebugDraw p_draw) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->debug_draw = p_draw; } void RendererViewport::viewport_set_measure_render_time(RID p_viewport, bool p_enable) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->measure_render_time = p_enable; } float RendererViewport::viewport_get_measured_render_time_cpu(RID p_viewport) const { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND_V(!viewport, 0); return double(viewport->time_cpu_end - viewport->time_cpu_begin) / 1000.0; } float RendererViewport::viewport_get_measured_render_time_gpu(RID p_viewport) const { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND_V(!viewport, 0); return double((viewport->time_gpu_end - viewport->time_gpu_begin) / 1000) / 1000.0; } void RendererViewport::viewport_set_snap_2d_transforms_to_pixel(RID p_viewport, bool p_enabled) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->snap_2d_transforms_to_pixel = p_enabled; } void RendererViewport::viewport_set_snap_2d_vertices_to_pixel(RID p_viewport, bool p_enabled) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->snap_2d_vertices_to_pixel = p_enabled; } void RendererViewport::viewport_set_default_canvas_item_texture_filter(RID p_viewport, RS::CanvasItemTextureFilter p_filter) { ERR_FAIL_COND_MSG(p_filter == RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT, "Viewport does not accept DEFAULT as texture filter (it's the topmost choice already).)"); - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->texture_filter = p_filter; } void RendererViewport::viewport_set_default_canvas_item_texture_repeat(RID p_viewport, RS::CanvasItemTextureRepeat p_repeat) { ERR_FAIL_COND_MSG(p_repeat == RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT, "Viewport does not accept DEFAULT as texture repeat (it's the topmost choice already).)"); - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); viewport->texture_repeat = p_repeat; } void RendererViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) { - Viewport *viewport = viewport_owner.getornull(p_viewport); + Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_COND(!viewport); RSG::storage->render_target_set_sdf_size_and_scale(viewport->render_target, p_size, p_scale); @@ -1099,7 +1167,7 @@ void RendererViewport::viewport_set_sdf_oversize_and_scale(RID p_viewport, RS::V bool RendererViewport::free(RID p_rid) { if (viewport_owner.owns(p_rid)) { - Viewport *viewport = viewport_owner.getornull(p_rid); + Viewport *viewport = viewport_owner.get_or_null(p_rid); RSG::storage->free(viewport->render_target); RSG::scene->free(viewport->shadow_atlas); @@ -1132,7 +1200,7 @@ void RendererViewport::handle_timestamp(String p_timestamp, uint64_t p_cpu_time, return; } - Viewport *viewport = viewport_owner.getornull(*vp); + Viewport *viewport = viewport_owner.get_or_null(*vp); if (!viewport) { return; } diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index f6095e18d7..5bb4dbbc6f 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -28,8 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifndef VISUALSERVERVIEWPORT_H -#define VISUALSERVERVIEWPORT_H +#ifndef RENDERER_VIEWPORT_H +#define RENDERER_VIEWPORT_H #include "core/templates/local_vector.h" #include "core/templates/rid_owner.h" @@ -49,12 +49,16 @@ public: bool use_xr; /* use xr interface to override camera positioning and projection matrices and control output */ - RS::ViewportScale3D scale_3d = RenderingServer::VIEWPORT_SCALE_3D_DISABLED; - + Size2i internal_size; Size2i size; RID camera; RID scenario; + RS::ViewportScaling3DMode scaling_3d_mode; + float scaling_3d_scale = 1.0; + float fsr_sharpness = 0.2f; + float fsr_mipmap_bias = 0.0f; + bool fsr_enabled; RS::ViewportUpdateMode update_mode; RID render_target; RID render_target_texture; @@ -207,7 +211,6 @@ public: void viewport_initialize(RID p_rid); void viewport_set_use_xr(RID p_viewport, bool p_use_xr); - void viewport_set_scale_3d(RID p_viewport, RenderingServer::ViewportScale3D p_scale_3d); void viewport_set_size(RID p_viewport, int p_width, int p_height); @@ -216,6 +219,12 @@ public: void viewport_set_active(RID p_viewport, bool p_active); void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport); + + void viewport_set_scaling_3d_mode(RID p_viewport, RS::ViewportScaling3DMode p_mode); + void viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale); + void viewport_set_fsr_sharpness(RID p_viewport, float p_sharpness); + void viewport_set_fsr_mipmap_bias(RID p_viewport, float p_mipmap_bias); + void viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode); void viewport_set_vflip(RID p_viewport, bool p_enable); @@ -282,4 +291,4 @@ public: virtual ~RendererViewport() {} }; -#endif // VISUALSERVERVIEWPORT_H +#endif // RENDERER_VIEWPORT_H diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index b302c6b793..dcbc5f5c8e 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -476,7 +476,9 @@ void RenderingDevice::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device_name"), &RenderingDevice::get_device_name); ClassDB::bind_method(D_METHOD("get_device_pipeline_cache_uuid"), &RenderingDevice::get_device_pipeline_cache_uuid); - ClassDB::bind_method(D_METHOD("get_memory_usage"), &RenderingDevice::get_memory_usage); + ClassDB::bind_method(D_METHOD("get_memory_usage", "type"), &RenderingDevice::get_memory_usage); + + ClassDB::bind_method(D_METHOD("get_driver_resource", "resource", "rid", "index"), &RenderingDevice::get_driver_resource); BIND_CONSTANT(BARRIER_MASK_RASTER); BIND_CONSTANT(BARRIER_MASK_COMPUTE); @@ -484,6 +486,20 @@ void RenderingDevice::_bind_methods() { BIND_CONSTANT(BARRIER_MASK_ALL); BIND_CONSTANT(BARRIER_MASK_NO_BARRIER); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DEVICE); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_INSTANCE); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_VIEW); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_SAMPLER); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_BUFFER); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE); + BIND_ENUM_CONSTANT(DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE); + BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4_UNORM_PACK8); BIND_ENUM_CONSTANT(DATA_FORMAT_R4G4B4A4_UNORM_PACK16); BIND_ENUM_CONSTANT(DATA_FORMAT_B4G4R4A4_UNORM_PACK16); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 2cf1f165dd..563a80c12c 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -60,6 +60,23 @@ public: DEVICE_DIRECTX }; + enum DriverResource { + DRIVER_RESOURCE_VULKAN_DEVICE = 0, + DRIVER_RESOURCE_VULKAN_PHYSICAL_DEVICE, + DRIVER_RESOURCE_VULKAN_INSTANCE, + DRIVER_RESOURCE_VULKAN_QUEUE, + DRIVER_RESOURCE_VULKAN_QUEUE_FAMILY_INDEX, + DRIVER_RESOURCE_VULKAN_IMAGE, + DRIVER_RESOURCE_VULKAN_IMAGE_VIEW, + DRIVER_RESOURCE_VULKAN_IMAGE_NATIVE_TEXTURE_FORMAT, + DRIVER_RESOURCE_VULKAN_SAMPLER, + DRIVER_RESOURCE_VULKAN_DESCRIPTOR_SET, + DRIVER_RESOURCE_VULKAN_BUFFER, + DRIVER_RESOURCE_VULKAN_COMPUTE_PIPELINE, + DRIVER_RESOURCE_VULKAN_RENDER_PIPELINE, + //next driver continue enum from 1000 to keep order + }; + enum ShaderStage { SHADER_STAGE_VERTEX, SHADER_STAGE_FRAGMENT, @@ -103,6 +120,7 @@ public: // features bool supports_multiview = false; // If true this device supports multiview options + bool supports_fsr_half_float = false; // If true this device supports FSR scaling 3D in half float mode, otherwise use the fallback mode }; typedef String (*ShaderSPIRVGetCacheKeyFunction)(const Capabilities *p_capabilities); @@ -1183,6 +1201,8 @@ public: virtual String get_device_name() const = 0; virtual String get_device_pipeline_cache_uuid() const = 0; + virtual uint64_t get_driver_resource(DriverResource p_resource, RID p_rid = RID(), uint64_t p_index = 0) = 0; + static RenderingDevice *get_singleton(); RenderingDevice(); @@ -1217,6 +1237,7 @@ protected: Vector<int64_t> _draw_list_switch_to_next_pass_split(uint32_t p_splits); }; +VARIANT_ENUM_CAST(RenderingDevice::DriverResource) VARIANT_ENUM_CAST(RenderingDevice::ShaderStage) VARIANT_ENUM_CAST(RenderingDevice::ShaderLanguage) VARIANT_ENUM_CAST(RenderingDevice::CompareOperator) diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp index fa3f2f3895..a21f28989b 100644 --- a/servers/rendering/rendering_device_binds.cpp +++ b/servers/rendering/rendering_device_binds.cpp @@ -171,7 +171,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String /* STEP 2, Compile the versions, add to shader file */ - for (Map<StringName, String>::Element *E = version_texts.front(); E; E = E->next()) { + for (const KeyValue<StringName, String> &E : version_texts) { Ref<RDShaderSPIRV> bytecode; bytecode.instantiate(); @@ -180,7 +180,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String if (code == String()) { continue; } - code = code.replace("VERSION_DEFINES", E->get()); + code = code.replace("VERSION_DEFINES", E.value); String error; Vector<uint8_t> spirv = RenderingDevice::get_singleton()->shader_compile_spirv_from_source(RD::ShaderStage(i), code, RD::SHADER_LANGUAGE_GLSL, &error, false); bytecode->set_stage_bytecode(RD::ShaderStage(i), spirv); @@ -195,7 +195,7 @@ Error RDShaderFile::parse_versions_from_text(const String &p_text, const String bytecode->set_stage_compile_error(RD::ShaderStage(i), error); } - set_bytecode(bytecode, E->key()); + set_bytecode(bytecode, E.key); } return errors_found ? ERR_PARSE_ERROR : OK; diff --git a/servers/rendering/rendering_device_binds.h b/servers/rendering/rendering_device_binds.h index ccc3e2fb39..2cf7821668 100644 --- a/servers/rendering/rendering_device_binds.h +++ b/servers/rendering/rendering_device_binds.h @@ -351,8 +351,8 @@ public: Vector<StringName> get_version_list() const { Vector<StringName> vnames; - for (Map<StringName, Ref<RDShaderSPIRV>>::Element *E = versions.front(); E; E = E->next()) { - vnames.push_back(E->key()); + for (const KeyValue<StringName, Ref<RDShaderSPIRV>> &E : versions) { + vnames.push_back(E.key); } vnames.sort_custom<StringName::AlphCompare>(); return vnames; @@ -371,9 +371,9 @@ public: if (base_error != "") { ERR_PRINT("Error parsing shader '" + p_file + "':\n\n" + base_error); } else { - for (Map<StringName, Ref<RDShaderSPIRV>>::Element *E = versions.front(); E; E = E->next()) { + for (KeyValue<StringName, Ref<RDShaderSPIRV>> &E : versions) { for (int i = 0; i < RD::SHADER_STAGE_MAX; i++) { - String error = E->get()->get_stage_compile_error(RD::ShaderStage(i)); + String error = E.value->get_stage_compile_error(RD::ShaderStage(i)); if (error != String()) { static const char *stage_str[RD::SHADER_STAGE_MAX] = { "vertex", @@ -383,7 +383,7 @@ public: "compute" }; - ERR_PRINT("Error parsing shader '" + p_file + "', version '" + String(E->key()) + "', stage '" + stage_str[i] + "':\n\n" + error); + ERR_PRINT("Error parsing shader '" + p_file + "', version '" + String(E.key) + "', stage '" + stage_str[i] + "':\n\n" + error); } } } @@ -427,7 +427,7 @@ protected: ClassDB::bind_method(D_METHOD("_set_versions", "versions"), &RDShaderFile::_set_versions); ClassDB::bind_method(D_METHOD("_get_versions"), &RDShaderFile::_get_versions); - ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_versions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL), "_set_versions", "_get_versions"); + ADD_PROPERTY(PropertyInfo(Variant::DICTIONARY, "_versions", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_versions", "_get_versions"); ADD_PROPERTY(PropertyInfo(Variant::STRING, "base_error"), "set_base_error", "get_base_error"); } }; diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index bed6ade1f6..2ce9a20b6b 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -38,13 +38,16 @@ #include "renderer_scene_cull.h" #include "rendering_server_globals.h" -// careful, these may run in different threads than the visual server +// careful, these may run in different threads than the rendering server int RenderingServerDefault::changes = 0; /* FREE */ void RenderingServerDefault::_free(RID p_rid) { + if (unlikely(p_rid.is_null())) { + return; + } if (RSG::storage->free(p_rid)) { return; } @@ -61,14 +64,8 @@ void RenderingServerDefault::_free(RID p_rid) { /* EVENT QUEUING */ -void RenderingServerDefault::request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) { - ERR_FAIL_NULL(p_where); - FrameDrawnCallbacks fdc; - fdc.object = p_where->get_instance_id(); - fdc.method = p_method; - fdc.param = p_userdata; - - frame_drawn_callbacks.push_back(fdc); +void RenderingServerDefault::request_frame_drawn_callback(const Callable &p_callable) { + frame_drawn_callbacks.push_back(p_callable); } void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { @@ -100,15 +97,13 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { RSG::scene->update_visibility_notifiers(); while (frame_drawn_callbacks.front()) { - Object *obj = ObjectDB::get_instance(frame_drawn_callbacks.front()->get().object); - if (obj) { - Callable::CallError ce; - const Variant *v = &frame_drawn_callbacks.front()->get().param; - obj->call(frame_drawn_callbacks.front()->get().method, &v, 1, ce); - if (ce.error != Callable::CallError::CALL_OK) { - String err = Variant::get_call_error_text(obj, frame_drawn_callbacks.front()->get().method, &v, 1, ce); - ERR_PRINT("Error calling frame drawn function: " + err); - } + Callable c = frame_drawn_callbacks.front()->get(); + Variant result; + Callable::CallError ce; + c.call(nullptr, 0, result, ce); + if (ce.error != Callable::CallError::CALL_OK) { + String err = Variant::get_callable_error_text(c, nullptr, 0, ce); + ERR_PRINT("Error calling frame drawn function: " + err); } frame_drawn_callbacks.pop_front(); diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 56e79b62f2..b50631bb21 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -58,13 +58,7 @@ class RenderingServerDefault : public RenderingServer { static int changes; RID test_cube; - struct FrameDrawnCallbacks { - ObjectID object; - StringName method; - Variant param; - }; - - List<FrameDrawnCallbacks> frame_drawn_callbacks; + List<Callable> frame_drawn_callbacks; static void _changes_changed() {} @@ -229,8 +223,8 @@ public: FUNC2SC(shader_get_param_list, RID, List<PropertyInfo> *) - FUNC3(shader_set_default_texture_param, RID, const StringName &, RID) - FUNC2RC(RID, shader_get_default_texture_param, RID, const StringName &) + FUNC4(shader_set_default_texture_param, RID, const StringName &, RID, int) + FUNC3RC(RID, shader_get_default_texture_param, RID, const StringName &, int) FUNC2RC(Variant, shader_get_param_default, RID, const StringName &) FUNC1RC(ShaderNativeSourceCode, shader_get_native_source_code, RID) @@ -487,6 +481,14 @@ public: FUNC1(particles_collision_height_field_update, RID) FUNC2(particles_collision_set_height_field_resolution, RID, ParticlesCollisionHeightfieldResolution) + /* FOG VOLUME */ + + FUNCRIDSPLIT(fog_volume) + + FUNC2(fog_volume_set_shape, RID, FogVolumeShape) + FUNC2(fog_volume_set_extents, RID, const Vector3 &) + FUNC2(fog_volume_set_material, RID, RID) + /* VISIBILITY_NOTIFIER */ FUNCRIDSPLIT(visibility_notifier) @@ -526,7 +528,6 @@ public: FUNCRIDSPLIT(viewport) FUNC2(viewport_set_use_xr, RID, bool) - FUNC2(viewport_set_scale_3d, RID, ViewportScale3D) FUNC3(viewport_set_size, RID, int, int) FUNC2(viewport_set_active, RID, bool) @@ -537,6 +538,11 @@ public: FUNC3(viewport_attach_to_screen, RID, const Rect2 &, int) FUNC2(viewport_set_render_direct_to_screen, RID, bool) + FUNC2(viewport_set_scaling_3d_mode, RID, ViewportScaling3DMode) + FUNC2(viewport_set_scaling_3d_scale, RID, float) + FUNC2(viewport_set_fsr_sharpness, RID, float) + FUNC2(viewport_set_fsr_mipmap_bias, RID, float) + FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode) FUNC1RC(RID, viewport_get_texture, RID) @@ -608,7 +614,7 @@ public: FUNC2(environment_set_bg_color, RID, const Color &) FUNC2(environment_set_bg_energy, RID, float) FUNC2(environment_set_canvas_max_layer, RID, int) - FUNC7(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource, const Color &) + FUNC6(environment_set_ambient_light, RID, const Color &, EnvironmentAmbientSource, float, float, EnvironmentReflectionSource) // FIXME: Disabled during Vulkan refactoring, should be ported. #if 0 @@ -629,7 +635,7 @@ public: FUNC7(environment_set_adjustment, RID, bool, float, float, float, bool, RID) FUNC9(environment_set_fog, RID, bool, const Color &, float, float, float, float, float, float) - FUNC10(environment_set_volumetric_fog, RID, bool, float, const Color &, float, float, float, float, bool, float) + FUNC13(environment_set_volumetric_fog, RID, bool, float, const Color &, const Color &, float, float, float, float, float, bool, float, float) FUNC2(environment_set_volumetric_fog_volume_size, int, int) FUNC1(environment_set_volumetric_fog_filter_active, bool) @@ -693,6 +699,8 @@ public: FUNC2(instance_set_extra_visibility_margin, RID, real_t) FUNC2(instance_set_visibility_parent, RID, RID) + FUNC2(instance_set_ignore_culling, RID, bool) + // don't use these in a game! FUNC2RC(Vector<ObjectID>, instances_cull_aabb, const AABB &, RID) FUNC3RC(Vector<ObjectID>, instances_cull_ray, const Vector3 &, const Vector3 &, RID) @@ -702,10 +710,10 @@ public: FUNC2(instance_geometry_set_cast_shadows_setting, RID, ShadowCastingSetting) FUNC2(instance_geometry_set_material_override, RID, RID) - FUNC5(instance_geometry_set_visibility_range, RID, float, float, float, float) + FUNC6(instance_geometry_set_visibility_range, RID, float, float, float, float, VisibilityRangeFadeMode) FUNC4(instance_geometry_set_lightmap, RID, RID, const Rect2 &, int) FUNC2(instance_geometry_set_lod_bias, RID, float) - + FUNC2(instance_geometry_set_transparency, RID, float) FUNC3(instance_geometry_set_shader_parameter, RID, const StringName &, const Variant &) FUNC2RC(Variant, instance_geometry_get_shader_parameter, RID, const StringName &) FUNC2RC(Variant, instance_geometry_get_shader_parameter_default_value, RID, const StringName &) @@ -870,7 +878,7 @@ public: /* EVENT QUEUING */ - virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) override; + virtual void request_frame_drawn_callback(const Callable &p_callable) override; virtual void draw(bool p_swap_buffers, double frame_step) override; virtual void sync() override; diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp index 4218214fda..50719ecfc3 100644 --- a/servers/rendering/shader_language.cpp +++ b/servers/rendering/shader_language.cpp @@ -930,7 +930,6 @@ void ShaderLanguage::clear() { error_set = false; error_str = ""; last_const = false; - pass_array = false; while (nodes) { Node *n = nodes; nodes = nodes->next; @@ -1078,6 +1077,9 @@ bool ShaderLanguage::_find_identifier(const BlockNode *p_block, bool p_allow_rea if (r_data_type) { *r_data_type = shader->uniforms[p_identifier].type; } + if (r_array_size) { + *r_array_size = shader->uniforms[p_identifier].array_size; + } if (r_type) { *r_type = IDENTIFIER_UNIFORM; } @@ -1597,7 +1599,8 @@ bool ShaderLanguage::_validate_operator(OperatorNode *p_op, DataType *r_ret_type } const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { - //constructors + // Constructors. + { "bool", TYPE_BOOL, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "bvec2", TYPE_BVEC2, { TYPE_BOOL, TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, @@ -1670,7 +1673,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mat3", TYPE_MAT3, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "mat4", TYPE_MAT4, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, - //conversion scalars + // Conversion scalars. { "int", TYPE_INT, { TYPE_BOOL, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "int", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, @@ -1692,7 +1695,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "bool", TYPE_BOOL, { TYPE_UINT, TYPE_VOID }, { "" }, TAG_GLOBAL, true }, { "bool", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, - //conversion vectors + // Conversion vectors. { "ivec2", TYPE_IVEC2, { TYPE_BVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "ivec2", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, @@ -1754,7 +1757,7 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, true }, { "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, - //conversion between matrixes + // Conversion between matrixes. { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, @@ -1763,43 +1766,58 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID }, { "" }, TAG_GLOBAL, false }, - //builtins - trigonometry + // Built-ins - trigonometric functions. + // radians { "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false }, { "radians", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false }, { "radians", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false }, { "radians", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "degrees" }, TAG_GLOBAL, false }, + // degrees + { "degrees", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false }, { "degrees", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false }, { "degrees", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false }, { "degrees", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "radians" }, TAG_GLOBAL, false }, + // sin + { "sin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "sin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "sin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "sin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, + // cos + { "cos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "cos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "cos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "cos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, + // tan + { "tan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "tan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "tan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, { "tan", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "angle" }, TAG_GLOBAL, false }, + // asin + { "asin", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asin", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asin", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asin", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // acos + { "acos", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acos", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acos", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acos", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // atan + { "atan", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false }, { "atan", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false }, { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "y_over_x" }, TAG_GLOBAL, false }, @@ -1809,66 +1827,101 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "atan", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "y", "x" }, TAG_GLOBAL, false }, { "atan", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "y", "x" }, TAG_GLOBAL, false }, + // sinh + { "sinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // cosh + { "cosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "cosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "cosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "cosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // tanh + { "tanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "tanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "tanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "tanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // asinh + { "asinh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asinh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asinh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "asinh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // acosh + { "acosh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acosh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acosh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "acosh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // atanh + { "atanh", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "atanh", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "atanh", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "atanh", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, - //builtins - exponential + // Builtins - exponential functions. + // pow + { "pow", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "pow", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "pow", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "pow", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, + + // exp + { "exp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // log + { "log", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // exp2 + { "exp2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "exp2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // log2 + { "log2", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log2", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log2", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "log2", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // sqrt + { "sqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // inversesqrt + { "inversesqrt", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "inversesqrt", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "inversesqrt", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "inversesqrt", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, - //builtins - common + + // Built-ins - common functions. + // abs + { "abs", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "abs", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "abs", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, @@ -1879,6 +1932,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "abs", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "abs", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // sign + { "sign", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sign", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sign", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, @@ -1889,31 +1944,50 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "sign", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "sign", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // floor + { "floor", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "floor", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "floor", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "floor", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // trunc + { "trunc", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "trunc", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "trunc", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "trunc", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // round + { "round", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "round", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "round", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "round", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // roundEven + { "roundEven", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "roundEven", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "roundEven", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "roundEven", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // ceil + { "ceil", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "ceil", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "ceil", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "ceil", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // fract + { "fract", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "fract", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "fract", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "fract", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // mod + { "mod", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "mod", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, @@ -1922,11 +1996,15 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, { "mod", TYPE_VEC4, { TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "x", "y" }, TAG_GLOBAL, false }, + // modf + { "modf", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true }, { "modf", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true }, { "modf", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true }, { "modf", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "x", "i" }, TAG_GLOBAL, true }, + // min + { "min", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "min", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -1951,6 +2029,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "min", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // max + { "max", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "max", TYPE_VEC2, { TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -1975,6 +2055,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "max", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // clamp + { "clamp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false }, { "clamp", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false }, { "clamp", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, false }, @@ -1999,6 +2081,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "clamp", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true }, { "clamp", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "minVal", "maxVal" }, TAG_GLOBAL, true }, + // mix + { "mix", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, { "mix", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_BVEC2, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, @@ -2010,6 +2094,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, { "mix", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b", "value" }, TAG_GLOBAL, false }, + // step + { "step", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, { "step", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, { "step", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, @@ -2017,6 +2103,9 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "step", TYPE_VEC2, { TYPE_FLOAT, TYPE_VEC2, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, { "step", TYPE_VEC3, { TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, { "step", TYPE_VEC4, { TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, { "edge", "x" }, TAG_GLOBAL, false }, + + // smoothstep + { "smoothstep", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, { "smoothstep", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, { "smoothstep", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, @@ -2025,77 +2114,127 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "smoothstep", TYPE_VEC3, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC3, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, { "smoothstep", TYPE_VEC4, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VEC4, TYPE_VOID }, { "edge0", "edge1", "value" }, TAG_GLOBAL, false }, + // isnan + { "isnan", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isnan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isnan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isnan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // isinf + { "isinf", TYPE_BOOL, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isinf", TYPE_BVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isinf", TYPE_BVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "isinf", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // floatBitsToInt + { "floatBitsToInt", TYPE_INT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToInt", TYPE_IVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToInt", TYPE_IVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToInt", TYPE_IVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, + // floatBitsToUint + { "floatBitsToUint", TYPE_UINT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToUint", TYPE_UVEC2, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToUint", TYPE_UVEC3, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "floatBitsToUint", TYPE_UVEC4, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, + // intBitsToFloat + { "intBitsToFloat", TYPE_FLOAT, { TYPE_INT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "intBitsToFloat", TYPE_VEC2, { TYPE_IVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "intBitsToFloat", TYPE_VEC3, { TYPE_IVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "intBitsToFloat", TYPE_VEC4, { TYPE_IVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, + // uintBitsToFloat + { "uintBitsToFloat", TYPE_FLOAT, { TYPE_UINT, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "uintBitsToFloat", TYPE_VEC2, { TYPE_UVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "uintBitsToFloat", TYPE_VEC3, { TYPE_UVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, { "uintBitsToFloat", TYPE_VEC4, { TYPE_UVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, true }, - //builtins - geometric + // Built-ins - geometric functions. + // length + + { "length", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "length", TYPE_FLOAT, { TYPE_VEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "length", TYPE_FLOAT, { TYPE_VEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "length", TYPE_FLOAT, { TYPE_VEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + + // distance + + { "distance", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "distance", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "distance", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "distance", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + + // dot + + { "dot", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "dot", TYPE_FLOAT, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "dot", TYPE_FLOAT, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "dot", TYPE_FLOAT, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + + // cross + { "cross", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + + // normalize + + { "normalize", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "v" }, TAG_GLOBAL, false }, { "normalize", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, false }, { "normalize", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "v" }, TAG_GLOBAL, false }, { "normalize", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, false }, + + // reflect + { "reflect", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "I", "N" }, TAG_GLOBAL, false }, + + // refract + { "refract", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "I", "N", "eta" }, TAG_GLOBAL, false }, + // faceforward + { "faceforward", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false }, { "faceforward", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false }, { "faceforward", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "N", "I", "Nref" }, TAG_GLOBAL, false }, + // matrixCompMult + { "matrixCompMult", TYPE_MAT2, { TYPE_MAT2, TYPE_MAT2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "matrixCompMult", TYPE_MAT3, { TYPE_MAT3, TYPE_MAT3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "matrixCompMult", TYPE_MAT4, { TYPE_MAT4, TYPE_MAT4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + // outerProduct + { "outerProduct", TYPE_MAT2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false }, { "outerProduct", TYPE_MAT3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false }, { "outerProduct", TYPE_MAT4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "c", "r" }, TAG_GLOBAL, false }, + // transpose + { "transpose", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "transpose", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "transpose", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, + // determinant + { "determinant", TYPE_FLOAT, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "determinant", TYPE_FLOAT, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "determinant", TYPE_FLOAT, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, + // inverse + { "inverse", TYPE_MAT2, { TYPE_MAT2, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "inverse", TYPE_MAT3, { TYPE_MAT3, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, { "inverse", TYPE_MAT4, { TYPE_MAT4, TYPE_VOID }, { "m" }, TAG_GLOBAL, false }, + // lessThan + { "lessThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "lessThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "lessThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2108,6 +2247,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "lessThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "lessThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // greaterThan + { "greaterThan", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "greaterThan", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "greaterThan", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2120,6 +2261,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "greaterThan", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "greaterThan", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // lessThanEqual + { "lessThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "lessThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "lessThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2132,6 +2275,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "lessThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "lessThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // greaterThanEqual + { "greaterThanEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "greaterThanEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "greaterThanEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2144,6 +2289,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "greaterThanEqual", TYPE_BVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, { "greaterThanEqual", TYPE_BVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, true }, + // equal + { "equal", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "equal", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "equal", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2160,6 +2307,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "equal", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "equal", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + // notEqual + { "notEqual", TYPE_BVEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "notEqual", TYPE_BVEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "notEqual", TYPE_BVEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, @@ -2176,19 +2325,27 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "notEqual", TYPE_BVEC3, { TYPE_BVEC3, TYPE_BVEC3, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, { "notEqual", TYPE_BVEC4, { TYPE_BVEC4, TYPE_BVEC4, TYPE_VOID }, { "a", "b" }, TAG_GLOBAL, false }, + // any + { "any", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "any", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "any", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // all + { "all", TYPE_BOOL, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "all", TYPE_BOOL, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "all", TYPE_BOOL, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, + // not + { "not", TYPE_BVEC2, { TYPE_BVEC2, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "not", TYPE_BVEC3, { TYPE_BVEC3, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, { "not", TYPE_BVEC4, { TYPE_BVEC4, TYPE_VOID }, { "x" }, TAG_GLOBAL, false }, - //builtins - texture + // Built-ins: texture functions. + // textureSize + { "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, { "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, { "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, @@ -2201,6 +2358,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBEARRAY, TYPE_INT, TYPE_VOID }, { "sampler", "lod" }, TAG_GLOBAL, true }, + // texture + { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, { "texture", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, @@ -2224,6 +2383,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, false }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, false }, + // textureProj + { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, { "textureProj", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true }, @@ -2243,6 +2404,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "bias" }, TAG_GLOBAL, true }, + // textureLod + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false }, { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, @@ -2255,6 +2418,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false }, { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, false }, + // texelFetch + { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, @@ -2265,6 +2430,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, + // textureProjLod + { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, @@ -2275,6 +2442,8 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureProjLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, { "textureProjLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID }, { "sampler", "coords", "lod" }, TAG_GLOBAL, true }, + // textureGrad + { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, @@ -2287,40 +2456,202 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBEARRAY, TYPE_VEC4, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords", "dPdx", "dPdy" }, TAG_GLOBAL, true }, + // textureGather + + { "textureGather", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID }, { "sampler", "coords" }, TAG_GLOBAL, true }, + { "textureGather", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_INT, TYPE_VOID }, { "sampler", "coords", "comp" }, TAG_GLOBAL, true }, + + // dFdx + { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdx", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdx", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdx", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, + // dFdy + { "dFdy", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdy", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdy", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "dFdy", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, + // fwidth + { "fwidth", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "fwidth", TYPE_VEC2, { TYPE_VEC2, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "fwidth", TYPE_VEC3, { TYPE_VEC3, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, { "fwidth", TYPE_VEC4, { TYPE_VEC4, TYPE_VOID }, { "p" }, TAG_GLOBAL, true }, - //sub-functions + // Sub-functions. + // array - //array { "length", TYPE_INT, { TYPE_VOID }, { "" }, TAG_ARRAY, true }, - // modern functions + // Modern functions. + // fma { "fma", TYPE_FLOAT, { TYPE_FLOAT, TYPE_FLOAT, TYPE_FLOAT, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false }, { "fma", TYPE_VEC2, { TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false }, { "fma", TYPE_VEC3, { TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false }, { "fma", TYPE_VEC4, { TYPE_VEC4, TYPE_VEC4, TYPE_VEC4, TYPE_VOID }, { "a", "b", "c" }, TAG_GLOBAL, false }, + // Packing/Unpacking functions. + + { "packHalf2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "packUnorm2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "packSnorm2x16", TYPE_UINT, { TYPE_VEC2, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "packUnorm4x8", TYPE_UINT, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "packSnorm4x8", TYPE_UINT, { TYPE_VEC4, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + + { "unpackHalf2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "unpackUnorm2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "unpackSnorm2x16", TYPE_VEC2, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "unpackUnorm4x8", TYPE_VEC4, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + { "unpackSnorm4x8", TYPE_VEC4, { TYPE_UINT, TYPE_VOID }, { "v" }, TAG_GLOBAL, true }, + + // bitfieldExtract + + { "bitfieldExtract", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_IVEC2, { TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_IVEC3, { TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_IVEC4, { TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + + { "bitfieldExtract", TYPE_UINT, { TYPE_UINT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_UVEC2, { TYPE_UVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_UVEC3, { TYPE_UVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldExtract", TYPE_UVEC4, { TYPE_UVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "value", "offset", "bits" }, TAG_GLOBAL, true }, + + // bitfieldInsert + + { "bitfieldInsert", TYPE_INT, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_IVEC2, { TYPE_IVEC2, TYPE_IVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_IVEC3, { TYPE_IVEC3, TYPE_IVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_IVEC4, { TYPE_IVEC4, TYPE_IVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + + { "bitfieldInsert", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + { "bitfieldInsert", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_INT, TYPE_INT, TYPE_VOID }, { "base", "insert", "offset", "bits" }, TAG_GLOBAL, true }, + + // bitfieldReverse + + { "bitfieldReverse", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + { "bitfieldReverse", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitfieldReverse", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + // bitCount + + { "bitCount", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + { "bitCount", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "bitCount", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + // findLSB + + { "findLSB", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + { "findLSB", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findLSB", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + // findMSB + + { "findMSB", TYPE_INT, { TYPE_INT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_IVEC2, { TYPE_IVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_IVEC3, { TYPE_IVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_IVEC4, { TYPE_IVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + { "findMSB", TYPE_UINT, { TYPE_UINT, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_UVEC2, { TYPE_UVEC2, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_UVEC3, { TYPE_UVEC3, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + { "findMSB", TYPE_UVEC4, { TYPE_UVEC4, TYPE_VOID }, { "value" }, TAG_GLOBAL, true }, + + // umulExtended + + { "umulExtended", TYPE_VOID, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true }, + { "umulExtended", TYPE_VOID, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true }, + { "umulExtended", TYPE_VOID, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true }, + { "umulExtended", TYPE_VOID, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true }, + + // imulExtended + + { "imulExtended", TYPE_VOID, { TYPE_INT, TYPE_INT, TYPE_INT, TYPE_INT, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true }, + { "imulExtended", TYPE_VOID, { TYPE_IVEC2, TYPE_IVEC2, TYPE_IVEC2, TYPE_IVEC2, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true }, + { "imulExtended", TYPE_VOID, { TYPE_IVEC3, TYPE_IVEC3, TYPE_IVEC3, TYPE_IVEC3, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true }, + { "imulExtended", TYPE_VOID, { TYPE_IVEC4, TYPE_IVEC4, TYPE_IVEC4, TYPE_IVEC4, TYPE_VOID }, { "x", "y", "msb", "lsb" }, TAG_GLOBAL, true }, + + // uaddCarry + + { "uaddCarry", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true }, + { "uaddCarry", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true }, + { "uaddCarry", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true }, + { "uaddCarry", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "y", "carry" }, TAG_GLOBAL, true }, + + // usubBorrow + + { "usubBorrow", TYPE_UINT, { TYPE_UINT, TYPE_UINT, TYPE_UINT, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true }, + { "usubBorrow", TYPE_UVEC2, { TYPE_UVEC2, TYPE_UVEC2, TYPE_UVEC2, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true }, + { "usubBorrow", TYPE_UVEC3, { TYPE_UVEC3, TYPE_UVEC3, TYPE_UVEC3, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true }, + { "usubBorrow", TYPE_UVEC4, { TYPE_UVEC4, TYPE_UVEC4, TYPE_UVEC4, TYPE_VOID }, { "x", "y", "borrow" }, TAG_GLOBAL, true }, + + // ldexp + + { "ldexp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_INT, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true }, + { "ldexp", TYPE_VEC2, { TYPE_VEC2, TYPE_IVEC2, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true }, + { "ldexp", TYPE_VEC3, { TYPE_VEC3, TYPE_IVEC3, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true }, + { "ldexp", TYPE_VEC4, { TYPE_VEC4, TYPE_IVEC4, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true }, + + // frexp + + { "frexp", TYPE_FLOAT, { TYPE_FLOAT, TYPE_INT, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true }, + { "frexp", TYPE_VEC2, { TYPE_VEC2, TYPE_IVEC2, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true }, + { "frexp", TYPE_VEC3, { TYPE_VEC3, TYPE_IVEC3, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true }, + { "frexp", TYPE_VEC4, { TYPE_VEC4, TYPE_IVEC4, TYPE_VOID }, { "x", "exp" }, TAG_GLOBAL, true }, + { nullptr, TYPE_VOID, { TYPE_VOID }, { "" }, TAG_GLOBAL, false } }; const ShaderLanguage::BuiltinFuncOutArgs ShaderLanguage::builtin_func_out_args[] = { - //constructors - { "modf", 1 }, - { nullptr, 0 } + { "modf", { 1, -1 } }, + { "umulExtended", { 2, 3 } }, + { "imulExtended", { 2, 3 } }, + { "uaddCarry", { 2, -1 } }, + { "usubBorrow", { 2, -1 } }, + { "ldexp", { 1, -1 } }, + { "frexp", { 1, -1 } }, + { nullptr, { 0, -1 } } +}; + +const ShaderLanguage::BuiltinFuncConstArgs ShaderLanguage::builtin_func_const_args[] = { + { "textureGather", 2, 0, 3 }, + { nullptr, 0, 0, 0 } }; bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionInfo &p_function_info, OperatorNode *p_func, DataType *r_ret_type, StringName *r_ret_type_str) { @@ -2384,6 +2715,13 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI failed_builtin = true; bool fail = false; for (int i = 0; i < argcount; i++) { + if (p_func->arguments[i + 1]->type == Node::TYPE_ARRAY) { + const ArrayNode *anode = static_cast<const ArrayNode *>(p_func->arguments[i + 1]); + if (anode->call_expression == nullptr && !anode->is_indexed()) { + fail = true; + break; + } + } if (get_scalar_type(args[i]) == args[i] && p_func->arguments[i + 1]->type == Node::TYPE_CONSTANT && convert_constant(static_cast<ConstantNode *>(p_func->arguments[i + 1]), builtin_func_defs[idx].args[i])) { //all good, but needs implicit conversion later } else if (args[i] != builtin_func_defs[idx].args[i]) { @@ -2407,100 +2745,153 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } 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 && p_func->arguments[arg_idx + 1]->type != Node::TYPE_MEMBER && p_func->arguments[arg_idx + 1]->type != Node::TYPE_ARRAY) { - _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member."); - return false; + { + int constarg_idx = 0; + while (builtin_func_const_args[constarg_idx].name) { + if (String(name) == builtin_func_const_args[constarg_idx].name) { + int arg = builtin_func_const_args[constarg_idx].arg + 1; + if (p_func->arguments.size() <= arg) { + break; } - if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) { - ArrayNode *mn = static_cast<ArrayNode *>(p_func->arguments[arg_idx + 1]); - if (mn->is_const) { - fail = true; - } - } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) { - MemberNode *mn = static_cast<MemberNode *>(p_func->arguments[arg_idx + 1]); - if (mn->basetype_const) { - fail = true; + int min = builtin_func_const_args[constarg_idx].min; + int max = builtin_func_const_args[constarg_idx].max; + + bool error = false; + if (p_func->arguments[arg]->type == Node::TYPE_VARIABLE) { + const VariableNode *vn = (VariableNode *)p_func->arguments[arg]; + + bool is_const = false; + ConstantNode::Value value; + value.sint = -1; + + _find_identifier(p_block, false, p_function_info, vn->name, nullptr, nullptr, &is_const, nullptr, nullptr, &value); + if (!is_const || value.sint < min || value.sint > max) { + error = true; } - } else { // TYPE_VARIABLE - VariableNode *vn = static_cast<VariableNode *>(p_func->arguments[arg_idx + 1]); - if (vn->is_const) { - fail = true; - } else { - StringName varname = vn->name; - if (shader->uniforms.has(varname)) { - fail = true; - } else { - if (shader->varyings.has(varname)) { - _set_error(vformat("Varyings cannot be passed for '%s' parameter!", "out")); - return false; - } - if (p_function_info.built_ins.has(varname)) { - BuiltInInfo info = p_function_info.built_ins[varname]; - if (info.constant) { - fail = true; - } + } else { + if (p_func->arguments[arg]->type == Node::TYPE_CONSTANT) { + ConstantNode *cn = (ConstantNode *)p_func->arguments[arg]; + + if (cn->get_datatype() == TYPE_INT && cn->values.size() == 1) { + int value = cn->values[0].sint; + + if (value < min || value > max) { + error = true; } + } else { + error = true; } + } else { + error = true; } } - if (fail) { - _set_error(vformat("Constant value cannot be passed for '%s' parameter!", "out")); + if (error) { + _set_error(vformat("Expected integer constant within %s..%s range.", min, max)); return false; } + } + constarg_idx++; + } + } - StringName var_name; - if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) { - var_name = static_cast<const ArrayNode *>(p_func->arguments[arg_idx + 1])->name; - } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) { - Node *n = static_cast<const MemberNode *>(p_func->arguments[arg_idx + 1])->owner; - while (n->type == Node::TYPE_MEMBER) { - n = static_cast<const MemberNode *>(n)->owner; - } - if (n->type != Node::TYPE_VARIABLE && n->type != Node::TYPE_ARRAY) { + //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) { + for (int arg = 0; arg < BuiltinFuncOutArgs::MAX_ARGS; arg++) { + int arg_idx = builtin_func_out_args[outarg_idx].arguments[arg]; + if (arg_idx == -1) { + break; + } + if (arg_idx < argcount) { + if (p_func->arguments[arg_idx + 1]->type != Node::TYPE_VARIABLE && p_func->arguments[arg_idx + 1]->type != Node::TYPE_MEMBER && p_func->arguments[arg_idx + 1]->type != Node::TYPE_ARRAY) { _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member."); return false; } - if (n->type == Node::TYPE_VARIABLE) { - var_name = static_cast<const VariableNode *>(n)->name; - } else { // TYPE_ARRAY - var_name = static_cast<const ArrayNode *>(n)->name; + + if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) { + ArrayNode *mn = static_cast<ArrayNode *>(p_func->arguments[arg_idx + 1]); + if (mn->is_const) { + fail = true; + } + } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) { + MemberNode *mn = static_cast<MemberNode *>(p_func->arguments[arg_idx + 1]); + if (mn->basetype_const) { + fail = true; + } + } else { // TYPE_VARIABLE + VariableNode *vn = static_cast<VariableNode *>(p_func->arguments[arg_idx + 1]); + if (vn->is_const) { + fail = true; + } else { + StringName varname = vn->name; + if (shader->uniforms.has(varname)) { + fail = true; + } else { + if (shader->varyings.has(varname)) { + _set_error(vformat("Varyings cannot be passed for '%s' parameter!", "out")); + return false; + } + if (p_function_info.built_ins.has(varname)) { + BuiltInInfo info = p_function_info.built_ins[varname]; + if (info.constant) { + fail = true; + } + } + } + } + } + if (fail) { + _set_error(vformat("Constant value cannot be passed for '%s' parameter!", "out")); + return false; } - } else { // TYPE_VARIABLE - 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) || p_function_info.built_ins.has(var_name)) { - valid = true; - break; + + StringName var_name; + if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_ARRAY) { + var_name = static_cast<const ArrayNode *>(p_func->arguments[arg_idx + 1])->name; + } else if (p_func->arguments[arg_idx + 1]->type == Node::TYPE_MEMBER) { + Node *n = static_cast<const MemberNode *>(p_func->arguments[arg_idx + 1])->owner; + while (n->type == Node::TYPE_MEMBER) { + n = static_cast<const MemberNode *>(n)->owner; + } + if (n->type != Node::TYPE_VARIABLE && n->type != Node::TYPE_ARRAY) { + _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' is not a variable, array or member."); + return false; + } + if (n->type == Node::TYPE_VARIABLE) { + var_name = static_cast<const VariableNode *>(n)->name; + } else { // TYPE_ARRAY + var_name = static_cast<const ArrayNode *>(n)->name; + } + } else { // TYPE_VARIABLE + var_name = static_cast<const VariableNode *>(p_func->arguments[arg_idx + 1])->name; } - if (b->parent_function) { - for (int i = 0; i < b->parent_function->arguments.size(); i++) { - if (b->parent_function->arguments[i].name == var_name) { - valid = true; - break; + const BlockNode *b = p_block; + bool valid = false; + while (b) { + if (b->variables.has(var_name) || p_function_info.built_ins.has(var_name)) { + valid = true; + break; + } + if (b->parent_function) { + for (int i = 0; i < b->parent_function->arguments.size(); i++) { + if (b->parent_function->arguments[i].name == var_name) { + valid = true; + break; + } } } + b = b->parent_block; } - b = b->parent_block; - } - if (!valid) { - _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable, array or member."); - return false; + if (!valid) { + _set_error("Argument " + itos(arg_idx + 1) + " of function '" + String(name) + "' can only take a local variable, array or member."); + return false; + } } } } - outarg_idx++; } //implicitly convert values if possible @@ -2560,6 +2951,11 @@ bool ShaderLanguage::_validate_function_call(BlockNode *p_block, const FunctionI } else { arg_name = get_datatype_name(args[i]); } + if (args3[i] > 0) { + arg_name += "["; + arg_name += itos(args3[i]); + arg_name += "]"; + } err += arg_name; } err += ")"; @@ -2900,98 +3296,306 @@ bool ShaderLanguage::is_float_type(DataType p_type) { } bool ShaderLanguage::is_sampler_type(DataType p_type) { return p_type == TYPE_SAMPLER2D || - p_type == TYPE_ISAMPLER2D || - p_type == TYPE_USAMPLER2D || - p_type == TYPE_SAMPLER2DARRAY || - p_type == TYPE_ISAMPLER2DARRAY || - p_type == TYPE_USAMPLER2DARRAY || - p_type == TYPE_SAMPLER3D || - p_type == TYPE_ISAMPLER3D || - p_type == TYPE_USAMPLER3D || - p_type == TYPE_SAMPLERCUBE || - p_type == TYPE_SAMPLERCUBEARRAY; + p_type == TYPE_ISAMPLER2D || + p_type == TYPE_USAMPLER2D || + p_type == TYPE_SAMPLER2DARRAY || + p_type == TYPE_ISAMPLER2DARRAY || + p_type == TYPE_USAMPLER2DARRAY || + p_type == TYPE_SAMPLER3D || + p_type == TYPE_ISAMPLER3D || + p_type == TYPE_USAMPLER3D || + p_type == TYPE_SAMPLERCUBE || + p_type == TYPE_SAMPLERCUBEARRAY; } -Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) { +Variant ShaderLanguage::constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint) { + int array_size = p_array_size; + if (p_value.size() > 0) { Variant value; switch (p_type) { case ShaderLanguage::TYPE_BOOL: - value = Variant(p_value[0].boolean); + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].boolean); + } + value = Variant(array); + } else { + value = Variant(p_value[0].boolean); + } break; case ShaderLanguage::TYPE_BVEC2: + array_size *= 2; + + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].boolean); + } + value = Variant(array); + } else { + value = Variant(p_value[0].boolean); + } + break; case ShaderLanguage::TYPE_BVEC3: + array_size *= 3; + + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].boolean); + } + value = Variant(array); + } else { + value = Variant(p_value[0].boolean); + } + break; case ShaderLanguage::TYPE_BVEC4: + array_size *= 4; + + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].boolean); + } + value = Variant(array); + } else { + value = Variant(p_value[0].boolean); + } + break; case ShaderLanguage::TYPE_INT: - value = Variant(p_value[0].sint); + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].sint); + } + value = Variant(array); + } else { + value = Variant(p_value[0].sint); + } break; case ShaderLanguage::TYPE_IVEC2: - value = Variant(Vector2(p_value[0].sint, p_value[1].sint)); + if (array_size > 0) { + array_size *= 2; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].sint); + } + value = Variant(array); + } else { + value = Variant(Vector2(p_value[0].sint, p_value[1].sint)); + } break; case ShaderLanguage::TYPE_IVEC3: - value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint)); + if (array_size > 0) { + array_size *= 3; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].sint); + } + value = Variant(array); + } else { + value = Variant(Vector3(p_value[0].sint, p_value[1].sint, p_value[2].sint)); + } break; case ShaderLanguage::TYPE_IVEC4: - value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint)); + if (array_size > 0) { + array_size *= 4; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].sint); + } + value = Variant(array); + } else { + value = Variant(Plane(p_value[0].sint, p_value[1].sint, p_value[2].sint, p_value[3].sint)); + } break; case ShaderLanguage::TYPE_UINT: - value = Variant(p_value[0].uint); + if (array_size > 0) { + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].uint); + } + value = Variant(array); + } else { + value = Variant(p_value[0].uint); + } break; case ShaderLanguage::TYPE_UVEC2: - value = Variant(Vector2(p_value[0].uint, p_value[1].uint)); + if (array_size > 0) { + array_size *= 2; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].uint); + } + value = Variant(array); + } else { + value = Variant(Vector2(p_value[0].uint, p_value[1].uint)); + } break; case ShaderLanguage::TYPE_UVEC3: - value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint)); + if (array_size > 0) { + array_size *= 3; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].uint); + } + value = Variant(array); + } else { + value = Variant(Vector3(p_value[0].uint, p_value[1].uint, p_value[2].uint)); + } break; case ShaderLanguage::TYPE_UVEC4: - value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint)); + if (array_size > 0) { + array_size *= 4; + + PackedInt32Array array = PackedInt32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].uint); + } + value = Variant(array); + } else { + value = Variant(Plane(p_value[0].uint, p_value[1].uint, p_value[2].uint, p_value[3].uint)); + } break; case ShaderLanguage::TYPE_FLOAT: - value = Variant(p_value[0].real); + if (array_size > 0) { + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i++) { + array.push_back(p_value[i].real); + } + value = Variant(array); + } else { + value = Variant(p_value[0].real); + } break; case ShaderLanguage::TYPE_VEC2: - value = Variant(Vector2(p_value[0].real, p_value[1].real)); + if (array_size > 0) { + array_size *= 2; + + PackedVector2Array array = PackedVector2Array(); + for (int i = 0; i < array_size; i += 2) { + array.push_back(Vector2(p_value[i].real, p_value[i + 1].real)); + } + value = Variant(array); + } else { + value = Variant(Vector2(p_value[0].real, p_value[1].real)); + } break; case ShaderLanguage::TYPE_VEC3: - value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real)); + if (array_size > 0) { + array_size *= 3; + + PackedVector3Array array = PackedVector3Array(); + for (int i = 0; i < array_size; i += 3) { + array.push_back(Vector3(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real)); + } + value = Variant(array); + } else { + value = Variant(Vector3(p_value[0].real, p_value[1].real, p_value[2].real)); + } break; case ShaderLanguage::TYPE_VEC4: - 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)); + if (array_size > 0) { + array_size *= 4; + + if (p_hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + PackedColorArray array = PackedColorArray(); + for (int i = 0; i < array_size; i += 4) { + array.push_back(Color(p_value[i].real, p_value[i + 1].real, p_value[i + 2].real, p_value[i + 3].real)); + } + value = Variant(array); + } else { + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i += 4) { + array.push_back(p_value[i].real); + array.push_back(p_value[i + 1].real); + array.push_back(p_value[i + 2].real); + array.push_back(p_value[i + 3].real); + } + value = Variant(array); + } } else { - 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)); + if (array_size > 0) { + array_size *= 4; + + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i += 4) { + array.push_back(p_value[i].real); + array.push_back(p_value[i + 1].real); + array.push_back(p_value[i + 2].real); + array.push_back(p_value[i + 3].real); + } + value = Variant(array); + } else { + value = Variant(Transform2D(p_value[0].real, p_value[2].real, p_value[1].real, p_value[3].real, 0.0, 0.0)); + } break; case ShaderLanguage::TYPE_MAT3: { - Basis p; - p[0][0] = p_value[0].real; - p[0][1] = p_value[1].real; - p[0][2] = p_value[2].real; - p[1][0] = p_value[3].real; - p[1][1] = p_value[4].real; - p[1][2] = p_value[5].real; - p[2][0] = p_value[6].real; - p[2][1] = p_value[7].real; - p[2][2] = p_value[8].real; - value = Variant(p); + if (array_size > 0) { + array_size *= 9; + + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i += 9) { + for (int j = 0; j < 9; j++) { + array.push_back(p_value[i + j].real); + } + } + value = Variant(array); + } else { + Basis p; + p[0][0] = p_value[0].real; + p[0][1] = p_value[1].real; + p[0][2] = p_value[2].real; + p[1][0] = p_value[3].real; + p[1][1] = p_value[4].real; + p[1][2] = p_value[5].real; + p[2][0] = p_value[6].real; + p[2][1] = p_value[7].real; + p[2][2] = p_value[8].real; + value = Variant(p); + } break; } case ShaderLanguage::TYPE_MAT4: { - Basis p; - p[0][0] = p_value[0].real; - p[0][1] = p_value[1].real; - p[0][2] = p_value[2].real; - p[1][0] = p_value[4].real; - p[1][1] = p_value[5].real; - p[1][2] = p_value[6].real; - p[2][0] = p_value[8].real; - p[2][1] = p_value[9].real; - p[2][2] = p_value[10].real; - Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real)); - value = Variant(t); + if (array_size > 0) { + array_size *= 16; + + PackedFloat32Array array = PackedFloat32Array(); + for (int i = 0; i < array_size; i += 16) { + for (int j = 0; j < 16; j++) { + array.push_back(p_value[i + j].real); + } + } + value = Variant(array); + } else { + Basis p; + p[0][0] = p_value[0].real; + p[0][1] = p_value[1].real; + p[0][2] = p_value[2].real; + p[1][0] = p_value[4].real; + p[1][1] = p_value[5].real; + p[1][2] = p_value[6].real; + p[2][0] = p_value[8].real; + p[2][1] = p_value[9].real; + p[2][2] = p_value[10].real; + Transform3D t = Transform3D(p, Vector3(p_value[3].real, p_value[7].real, p_value[11].real)); + value = Variant(t); + } break; } case ShaderLanguage::TYPE_ISAMPLER2DARRAY: @@ -3027,31 +3631,50 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.type = Variant::NIL; break; case ShaderLanguage::TYPE_BOOL: - pi.type = Variant::BOOL; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::BOOL; + } break; case ShaderLanguage::TYPE_BVEC2: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y"; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y"; + } break; case ShaderLanguage::TYPE_BVEC3: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z"; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y,z"; + } break; case ShaderLanguage::TYPE_BVEC4: - pi.type = Variant::INT; - pi.hint = PROPERTY_HINT_FLAGS; - pi.hint_string = "x,y,z,w"; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::INT; + pi.hint = PROPERTY_HINT_FLAGS; + pi.hint_string = "x,y,z,w"; + } break; case ShaderLanguage::TYPE_UINT: case ShaderLanguage::TYPE_INT: { - pi.type = Variant::INT; - if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]); + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_INT32_ARRAY; + } else { + pi.type = Variant::INT; + if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { + pi.hint = PROPERTY_HINT_RANGE; + pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]); + } } - } break; case ShaderLanguage::TYPE_IVEC2: case ShaderLanguage::TYPE_IVEC3: @@ -3062,59 +3685,106 @@ PropertyInfo ShaderLanguage::uniform_to_property_info(const ShaderNode::Uniform pi.type = Variant::PACKED_INT32_ARRAY; } break; case ShaderLanguage::TYPE_FLOAT: { - pi.type = Variant::FLOAT; - if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { - pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]); + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } else { + pi.type = Variant::FLOAT; + if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { + pi.hint = PROPERTY_HINT_RANGE; + pi.hint_string = rtos(p_uniform.hint_range[0]) + "," + rtos(p_uniform.hint_range[1]) + "," + rtos(p_uniform.hint_range[2]); + } } - } break; case ShaderLanguage::TYPE_VEC2: - pi.type = Variant::VECTOR2; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_VECTOR2_ARRAY; + } else { + pi.type = Variant::VECTOR2; + } break; case ShaderLanguage::TYPE_VEC3: - pi.type = Variant::VECTOR3; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_VECTOR3_ARRAY; + } else { + pi.type = Variant::VECTOR3; + } break; case ShaderLanguage::TYPE_VEC4: { - if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { - pi.type = Variant::COLOR; + if (p_uniform.array_size > 0) { + if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + pi.type = Variant::PACKED_COLOR_ARRAY; + } else { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } } else { - pi.type = Variant::PLANE; + if (p_uniform.hint == ShaderLanguage::ShaderNode::Uniform::HINT_COLOR) { + pi.type = Variant::COLOR; + } else { + pi.type = Variant::PLANE; + } } } break; case ShaderLanguage::TYPE_MAT2: - pi.type = Variant::TRANSFORM2D; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } else { + pi.type = Variant::TRANSFORM2D; + } break; case ShaderLanguage::TYPE_MAT3: - pi.type = Variant::BASIS; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } else { + pi.type = Variant::BASIS; + } break; case ShaderLanguage::TYPE_MAT4: - pi.type = Variant::TRANSFORM3D; + if (p_uniform.array_size > 0) { + pi.type = Variant::PACKED_FLOAT32_ARRAY; + } else { + pi.type = Variant::TRANSFORM3D; + } break; case ShaderLanguage::TYPE_SAMPLER2D: case ShaderLanguage::TYPE_ISAMPLER2D: case ShaderLanguage::TYPE_USAMPLER2D: { - pi.type = Variant::OBJECT; + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + } else { + pi.type = Variant::OBJECT; + } pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture2D"; } break; case ShaderLanguage::TYPE_SAMPLER2DARRAY: case ShaderLanguage::TYPE_ISAMPLER2DARRAY: case ShaderLanguage::TYPE_USAMPLER2DARRAY: { - pi.type = Variant::OBJECT; + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + } else { + pi.type = Variant::OBJECT; + } pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "TextureLayered"; } break; case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: { - pi.type = Variant::OBJECT; + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + } else { + pi.type = Variant::OBJECT; + } pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture3D"; } break; case ShaderLanguage::TYPE_SAMPLERCUBE: case ShaderLanguage::TYPE_SAMPLERCUBEARRAY: { - pi.type = Variant::OBJECT; + if (p_uniform.array_size > 0) { + pi.type = Variant::ARRAY; + } else { + pi.type = Variant::OBJECT; + } pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "TextureLayered"; } break; @@ -3203,16 +3873,16 @@ void ShaderLanguage::get_keyword_list(List<String> *r_keywords) { bool ShaderLanguage::is_control_flow_keyword(String p_keyword) { return p_keyword == "break" || - p_keyword == "case" || - p_keyword == "continue" || - p_keyword == "default" || - p_keyword == "do" || - p_keyword == "else" || - p_keyword == "for" || - p_keyword == "if" || - p_keyword == "return" || - p_keyword == "switch" || - p_keyword == "while"; + p_keyword == "case" || + p_keyword == "continue" || + p_keyword == "default" || + p_keyword == "do" || + p_keyword == "else" || + p_keyword == "for" || + p_keyword == "if" || + p_keyword == "return" || + p_keyword == "switch" || + p_keyword == "while"; } void ShaderLanguage::get_builtin_funcs(List<String> *r_keywords) { @@ -3537,9 +4207,9 @@ bool ShaderLanguage::_propagate_function_call_sampler_uniform_settings(StringNam arg->tex_argument_check = true; arg->tex_argument_filter = p_filter; arg->tex_argument_repeat = p_repeat; - for (Map<StringName, Set<int>>::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) { - for (Set<int>::Element *F = E->get().front(); F; F = F->next()) { - if (!_propagate_function_call_sampler_uniform_settings(E->key(), F->get(), p_filter, p_repeat)) { + for (KeyValue<StringName, Set<int>> &E : arg->tex_argument_connect) { + for (Set<int>::Element *F = E.value.front(); F; F = F->next()) { + if (!_propagate_function_call_sampler_uniform_settings(E.key, F->get(), p_filter, p_repeat)) { return false; } } @@ -3571,9 +4241,9 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa arg->tex_builtin_check = true; arg->tex_builtin = p_builtin; - for (Map<StringName, Set<int>>::Element *E = arg->tex_argument_connect.front(); E; E = E->next()) { - for (Set<int>::Element *F = E->get().front(); F; F = F->next()) { - if (!_propagate_function_call_sampler_builtin_reference(E->key(), F->get(), p_builtin)) { + for (KeyValue<StringName, Set<int>> &E : arg->tex_argument_connect) { + for (Set<int>::Element *F = E.value.front(); F; F = F->next()) { + if (!_propagate_function_call_sampler_builtin_reference(E.key, F->get(), p_builtin)) { return false; } } @@ -3585,6 +4255,116 @@ bool ShaderLanguage::_propagate_function_call_sampler_builtin_reference(StringNa ERR_FAIL_V(false); //bug? function not found } +ShaderLanguage::Node *ShaderLanguage::_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size) { + int array_size = 0; + + Node *n = _parse_and_reduce_expression(p_block, p_function_info); + if (n) { + if (n->type == Node::TYPE_VARIABLE) { + VariableNode *vn = static_cast<VariableNode *>(n); + if (vn) { + ConstantNode::Value v; + DataType data_type; + bool is_const = false; + + _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v); + + if (is_const) { + if (data_type == TYPE_INT) { + int32_t value = v.sint; + if (value > 0) { + array_size = value; + } + } else if (data_type == TYPE_UINT) { + uint32_t value = v.uint; + if (value > 0U) { + array_size = value; + } + } + } + } + } else if (n->type == Node::TYPE_OPERATOR) { + _set_error("Array size expressions are not yet implemented."); + return nullptr; + } + } + + r_array_size = array_size; + return n; +} + +Error ShaderLanguage::_parse_global_array_size(int &r_array_size) { + if (r_array_size > 0) { + _set_error("Array size is already defined!"); + return ERR_PARSE_ERROR; + } + TkPos pos = _get_tkpos(); + Token tk = _get_token(); + + int array_size = 0; + + if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) { + _set_tkpos(pos); + Node *n = _parse_array_size(nullptr, FunctionInfo(), array_size); + if (!n) { + return ERR_PARSE_ERROR; + } + } else if (((int)tk.constant) > 0) { + array_size = (uint32_t)tk.constant; + } + + if (array_size <= 0) { + _set_error("Expected single integer constant > 0"); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']'"); + return ERR_PARSE_ERROR; + } + + r_array_size = array_size; + return OK; +} + +Error ShaderLanguage::_parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, ArrayDeclarationNode *p_node, ArrayDeclarationNode::Declaration *p_decl, int &r_array_size, bool &r_is_unknown_size) { + TkPos pos = _get_tkpos(); + Token tk = _get_token(); + + if (tk.type == TK_BRACKET_CLOSE) { + r_is_unknown_size = true; + } else { + if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) { + _set_tkpos(pos); + int array_size = 0; + Node *n = _parse_array_size(p_block, p_function_info, array_size); + if (!n) { + return ERR_PARSE_ERROR; + } + p_decl->size = array_size; + p_node->size_expression = n; + } else if (((int)tk.constant) > 0) { + p_decl->size = (uint32_t)tk.constant; + } + + if (p_decl->size <= 0) { + _set_error("Expected single integer constant > 0"); + return ERR_PARSE_ERROR; + } + + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']'"); + return ERR_PARSE_ERROR; + } + + r_array_size = p_decl->size; + } + + return OK; +} + ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info) { DataType type = TYPE_VOID; String struct_name = ""; @@ -3721,9 +4501,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc if (!is_token_variable_datatype(tk.type)) { _set_tkpos(prev_pos); - pass_array = true; Node *n = _parse_and_reduce_expression(p_block, p_function_info); - pass_array = false; if (!n) { _set_error("Invalid data type for array"); @@ -3813,7 +4591,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_array_constructor(BlockNode *p_bloc return nullptr; } - if (!_compare_datatypes(p_type, p_struct_name, 0, n->get_datatype(), n->get_datatype_name(), 0)) { + if (!_compare_datatypes(p_type, p_struct_name, 0, n->get_datatype(), n->get_datatype_name(), n->get_array_size())) { return nullptr; } @@ -4061,9 +4839,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons int carg = -1; - pass_array = true; bool ok = _parse_function_arguments(p_block, p_function_info, func, &carg); - pass_array = false; // Check if block has a variable with the same name as function to prevent shader crash. ShaderLanguage::BlockNode *bnode = p_block; @@ -4144,7 +4920,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons bool error = false; Node *n = func->arguments[argidx]; if (n->type == Node::TYPE_CONSTANT || n->type == Node::TYPE_OPERATOR) { - error = true; + if (!call_function->arguments[i].is_const) { + error = true; + } } else if (n->type == Node::TYPE_ARRAY) { ArrayNode *an = static_cast<ArrayNode *>(n); if (an->call_expression != nullptr || an->is_const) { @@ -4315,62 +5093,58 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons Node *assign_expression = nullptr; if (array_size > 0) { - if (!pass_array) { - tk = _get_token(); + prepos = _get_tkpos(); + tk = _get_token(); - if (tk.type != TK_BRACKET_OPEN && tk.type != TK_PERIOD && tk.type != TK_OP_ASSIGN) { - _set_error("Expected '[','.' or '='"); + if (tk.type == TK_OP_ASSIGN) { + if (is_const) { + _set_error("Constants cannot be modified."); + return nullptr; + } + assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size); + if (!assign_expression) { + return nullptr; + } + } else if (tk.type == TK_PERIOD) { + completion_class = TAG_ARRAY; + p_block->block_tag = SubClassTag::TAG_ARRAY; + call_expression = _parse_and_reduce_expression(p_block, p_function_info); + p_block->block_tag = SubClassTag::TAG_GLOBAL; + if (!call_expression) { + return nullptr; + } + data_type = call_expression->get_datatype(); + } else if (tk.type == TK_BRACKET_OPEN) { // indexing + index_expression = _parse_and_reduce_expression(p_block, p_function_info); + if (!index_expression) { return nullptr; } - if (tk.type == TK_OP_ASSIGN) { - if (is_const) { - _set_error("Constants cannot be modified."); - return nullptr; - } - assign_expression = _parse_array_constructor(p_block, p_function_info, data_type, struct_name, array_size); - if (!assign_expression) { - return nullptr; - } - } else if (tk.type == TK_PERIOD) { - completion_class = TAG_ARRAY; - p_block->block_tag = SubClassTag::TAG_ARRAY; - call_expression = _parse_and_reduce_expression(p_block, p_function_info); - p_block->block_tag = SubClassTag::TAG_GLOBAL; - if (!call_expression) { - return nullptr; - } - data_type = call_expression->get_datatype(); - } else { // indexing - index_expression = _parse_and_reduce_expression(p_block, p_function_info); - if (!index_expression) { - return nullptr; - } - - if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) { - _set_error("Only integer expressions are allowed for indexing"); - return nullptr; - } + if (index_expression->get_array_size() != 0 || (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT)) { + _set_error("Only integer expressions are allowed for indexing."); + return nullptr; + } - if (index_expression->type == Node::TYPE_CONSTANT) { - ConstantNode *cnode = (ConstantNode *)index_expression; - if (cnode) { - if (!cnode->values.is_empty()) { - int value = cnode->values[0].sint; - if (value < 0 || value >= array_size) { - _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); - return nullptr; - } + if (index_expression->type == Node::TYPE_CONSTANT) { + ConstantNode *cnode = (ConstantNode *)index_expression; + if (cnode) { + if (!cnode->values.is_empty()) { + int value = cnode->values[0].sint; + if (value < 0 || value >= array_size) { + _set_error(vformat("Index [%s] out of range [%s..%s]", value, 0, array_size - 1)); + return nullptr; } } } + } - tk = _get_token(); - if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); - return nullptr; - } + tk = _get_token(); + if (tk.type != TK_BRACKET_CLOSE) { + _set_error("Expected ']'"); + return nullptr; } + } else { + _set_tkpos(prepos); } ArrayNode *arrname = alloc_node<ArrayNode>(); @@ -4770,8 +5544,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } - if (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT) { - _set_error("Only integer expressions are allowed for indexing"); + if (index_expression->get_array_size() != 0 || (index_expression->get_datatype() != TYPE_INT && index_expression->get_datatype() != TYPE_UINT)) { + _set_error("Only integer expressions are allowed for indexing."); return nullptr; } @@ -4795,10 +5569,6 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } mn->index_expression = index_expression; } else { - if (!pass_array) { - _set_error("Expected '[','.' or '='"); - return nullptr; - } _set_tkpos(prev_pos); } } @@ -4820,8 +5590,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } - if (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT) { - _set_error("Only integer datatypes are allowed for indexing"); + if (index->get_array_size() != 0 || (index->get_datatype() != TYPE_INT && index->get_datatype() != TYPE_UINT)) { + _set_error("Only integer expressions are allowed for indexing."); return nullptr; } @@ -5243,7 +6013,9 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } #if DEBUG_ENABLED - if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) && expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT) { + if (check_warnings && HAS_WARNING(ShaderWarning::FLOAT_COMPARISON_FLAG) && (op == OP_EQUAL || op == OP_NOT_EQUAL) && + (!expression[i - 1].is_op && !expression[i + 1].is_op) && + (expression[i - 1].node->get_datatype() == TYPE_FLOAT && expression[i + 1].node->get_datatype() == TYPE_FLOAT)) { _add_line_warning(ShaderWarning::FLOAT_COMPARISON); } #endif // DEBUG_ENABLED @@ -5301,7 +6073,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons _set_error("Invalid arguments to unary operator '" + get_operator_text(op->op) + "' :" + at); return nullptr; } - expression.remove(i + 1); + expression.remove_at(i + 1); } } else if (is_ternary) { @@ -5341,7 +6113,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } for (int i = 0; i < 4; i++) { - expression.remove(next_op); + expression.remove_at(next_op); } } else { @@ -5402,8 +6174,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons return nullptr; } - expression.remove(next_op); - expression.remove(next_op); + expression.remove_at(next_op); + expression.remove_at(next_op); } } @@ -5607,11 +6379,46 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun Node *vardecl = nullptr; while (true) { - if (tk.type != TK_IDENTIFIER) { - _set_error("Expected identifier after type"); + bool unknown_size = false; + int array_size = 0; + + ArrayDeclarationNode *anode = nullptr; + ArrayDeclarationNode::Declaration adecl; + + if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { + _set_error("Expected identifier or '[' after type."); return ERR_PARSE_ERROR; } + if (tk.type == TK_BRACKET_OPEN) { + anode = alloc_node<ArrayDeclarationNode>(); + + if (is_struct) { + anode->struct_name = struct_name; + anode->datatype = TYPE_STRUCT; + } else { + anode->datatype = type; + } + + anode->precision = precision; + anode->is_const = is_const; + vardecl = (Node *)anode; + + adecl.size = 0U; + adecl.single_expression = false; + + Error error = _parse_local_array_size(p_block, p_function_info, anode, &adecl, array_size, unknown_size); + if (error != OK) { + return error; + } + tk = _get_token(); + + if (tk.type != TK_IDENTIFIER) { + _set_error("Expected identifier!"); + return ERR_PARSE_ERROR; + } + } + StringName name = tk.text; ShaderLanguage::IdentifierType itype; if (_find_identifier(p_block, true, p_function_info, name, (ShaderLanguage::DataType *)nullptr, &itype)) { @@ -5621,6 +6428,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } } + adecl.name = name; + #ifdef DEBUG_ENABLED if (check_warnings && HAS_WARNING(ShaderWarning::UNUSED_LOCAL_VARIABLE_FLAG)) { if (p_block && p_block->parent_function) { @@ -5639,95 +6448,47 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun var.type = type; var.precision = precision; var.line = tk_line; - var.array_size = 0; + var.array_size = array_size; var.is_const = is_const; var.struct_name = struct_name; tk = _get_token(); if (tk.type == TK_BRACKET_OPEN) { - bool unknown_size = false; + if (var.array_size > 0 || unknown_size) { + _set_error("Array size is already defined!"); + return ERR_PARSE_ERROR; + } if (RenderingServer::get_singleton()->is_low_end() && is_const) { _set_error("Local const arrays are supported only on high-end platform!"); return ERR_PARSE_ERROR; } - ArrayDeclarationNode *node = alloc_node<ArrayDeclarationNode>(); + anode = alloc_node<ArrayDeclarationNode>(); if (is_struct) { - node->struct_name = struct_name; - node->datatype = TYPE_STRUCT; + anode->struct_name = struct_name; + anode->datatype = TYPE_STRUCT; } else { - node->datatype = type; + anode->datatype = type; } - node->precision = precision; - node->is_const = is_const; - vardecl = (Node *)node; - - ArrayDeclarationNode::Declaration decl; - decl.name = name; - decl.size = 0U; - decl.single_expression = false; - - pos = _get_tkpos(); - tk = _get_token(); - - if (tk.type == TK_BRACKET_CLOSE) { - unknown_size = true; - } else { - if (tk.type != TK_INT_CONSTANT || ((int)tk.constant) <= 0) { - _set_tkpos(pos); - Node *n = _parse_and_reduce_expression(p_block, p_function_info); - if (n) { - if (n->type == Node::TYPE_VARIABLE) { - VariableNode *vn = static_cast<VariableNode *>(n); - if (vn) { - ConstantNode::Value v; - DataType data_type; - - _find_identifier(p_block, false, p_function_info, vn->name, &data_type, nullptr, &is_const, nullptr, nullptr, &v); - - if (is_const) { - if (data_type == TYPE_INT) { - int32_t value = v.sint; - if (value > 0) { - node->size_expression = n; - decl.size = (uint32_t)value; - } - } else if (data_type == TYPE_UINT) { - uint32_t value = v.uint; - if (value > 0U) { - node->size_expression = n; - decl.size = value; - } - } - } - } - } else if (n->type == Node::TYPE_OPERATOR) { - _set_error("Array size expressions are not yet implemented."); - return ERR_PARSE_ERROR; - } - } - } else if (((int)tk.constant) > 0) { - decl.size = (uint32_t)tk.constant; - } + anode->precision = precision; + anode->is_const = is_const; + vardecl = (Node *)anode; - if (decl.size == 0U) { - _set_error("Expected integer constant > 0 or ']'"); - return ERR_PARSE_ERROR; - } - tk = _get_token(); + adecl.size = 0U; + adecl.single_expression = false; - if (tk.type != TK_BRACKET_CLOSE) { - _set_error("Expected ']'"); - return ERR_PARSE_ERROR; - } - var.array_size = decl.size; + Error error = _parse_local_array_size(p_block, p_function_info, anode, &adecl, var.array_size, unknown_size); + if (error != OK) { + return error; } + tk = _get_token(); + } + if (var.array_size > 0 || unknown_size) { bool full_def = false; - tk = _get_token(); if (tk.type == TK_OP_ASSIGN) { if (RenderingServer::get_singleton()->is_low_end()) { _set_error("Array initialization is supported only on high-end platform!"); @@ -5739,16 +6500,14 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun if (tk.type == TK_IDENTIFIER) { // a function call array initialization _set_tkpos(prev_pos); - pass_array = true; Node *n = _parse_and_reduce_expression(p_block, p_function_info); - pass_array = false; if (!n) { _set_error("Expected correct array initializer!"); return ERR_PARSE_ERROR; } else { if (unknown_size) { - decl.size = n->get_array_size(); + adecl.size = n->get_array_size(); var.array_size = n->get_array_size(); } @@ -5756,8 +6515,8 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } - decl.single_expression = true; - decl.initializer.push_back(n); + adecl.single_expression = true; + adecl.initializer.push_back(n); } tk = _get_token(); @@ -5896,7 +6655,7 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_PARSE_ERROR; } - if (node->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { + if (anode->is_const && n->type == Node::TYPE_OPERATOR && ((OperatorNode *)n)->op == OP_CALL) { _set_error("Expected constant expression"); return ERR_PARSE_ERROR; } @@ -5907,13 +6666,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun tk = _get_token(); if (tk.type == TK_COMMA) { - decl.initializer.push_back(n); + adecl.initializer.push_back(n); continue; } else if (!curly && tk.type == TK_PARENTHESIS_CLOSE) { - decl.initializer.push_back(n); + adecl.initializer.push_back(n); break; } else if (curly && tk.type == TK_CURLY_BRACKET_CLOSE) { - decl.initializer.push_back(n); + adecl.initializer.push_back(n); break; } else { if (curly) { @@ -5925,9 +6684,9 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } } if (unknown_size) { - decl.size = decl.initializer.size(); - var.array_size = decl.initializer.size(); - } else if (decl.initializer.size() != var.array_size) { + adecl.size = adecl.initializer.size(); + var.array_size = adecl.initializer.size(); + } else if (adecl.initializer.size() != var.array_size) { _set_error("Array size mismatch"); return ERR_PARSE_ERROR; } @@ -5939,13 +6698,13 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun _set_error("Expected array initialization"); return ERR_PARSE_ERROR; } - if (node->is_const) { + if (anode->is_const) { _set_error("Expected initialization of constant"); return ERR_PARSE_ERROR; } } - node->declarations.push_back(decl); + anode->declarations.push_back(adecl); } else if (tk.type == TK_OP_ASSIGN) { VariableDeclarationNode *node = alloc_node<VariableDeclarationNode>(); if (is_struct) { @@ -6431,11 +7190,6 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun //check return type BlockNode *b = p_block; - if (b && b->parent_function && p_function_info.main_function) { - _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name)); - return ERR_PARSE_ERROR; - } - while (b && !b->parent_function) { b = b->parent_block; } @@ -6445,6 +7199,11 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun return ERR_BUG; } + if (b && b->parent_function && p_function_info.main_function) { + _set_error(vformat("Using 'return' in '%s' processor function results in undefined behavior!", b->parent_function->name)); + return ERR_PARSE_ERROR; + } + String return_struct_name = String(b->parent_function->return_struct_name); String array_size_string; @@ -6466,12 +7225,10 @@ Error ShaderLanguage::_parse_block(BlockNode *p_block, const FunctionInfo &p_fun } else { _set_tkpos(pos); //rollback, wants expression - pass_array = true; Node *expr = _parse_and_reduce_expression(p_block, p_function_info); if (!expr) { return ERR_PARSE_ERROR; } - pass_array = false; if (b->parent_function->return_type != expr->get_datatype() || b->parent_function->return_array_size != expr->get_array_size() || return_struct_name != expr->get_datatype_name()) { _set_error("Expected return with an expression of type '" + (return_struct_name != "" ? return_struct_name : get_datatype_name(b->parent_function->return_type)) + array_size_string + "'"); @@ -6683,6 +7440,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); int texture_uniforms = 0; + int texture_binding = 0; int uniforms = 0; int instance_index = 0; ShaderNode::Uniform::Scope uniform_scope = ShaderNode::Uniform::SCOPE_LOCAL; @@ -6793,8 +7551,23 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _set_error("void datatype not allowed here"); return ERR_PARSE_ERROR; } - tk = _get_token(); + + if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { + _set_error("Expected identifier or '['."); + return ERR_PARSE_ERROR; + } + + int array_size = 0; + + if (tk.type == TK_BRACKET_OPEN) { + Error error = _parse_global_array_size(array_size); + if (error != OK) { + return error; + } + tk = _get_token(); + } + if (tk.type != TK_IDENTIFIER) { _set_error("Expected identifier!"); return ERR_PARSE_ERROR; @@ -6805,41 +7578,29 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct member->datatype = type; member->struct_name = struct_name; member->name = tk.text; + member->array_size = array_size; if (member_names.has(member->name)) { _set_error("Redefinition of '" + String(member->name) + "'"); return ERR_PARSE_ERROR; } member_names.insert(member->name); - tk = _get_token(); - if (tk.type == TK_BRACKET_OPEN) { - tk = _get_token(); - if (tk.type == TK_INT_CONSTANT && tk.constant > 0) { - member->array_size = (int)tk.constant; - tk = _get_token(); - if (tk.type == TK_BRACKET_CLOSE) { - tk = _get_token(); - if (tk.type != TK_SEMICOLON) { - _set_error("Expected ';'"); - return ERR_PARSE_ERROR; - } - } else { - _set_error("Expected ']'"); - return ERR_PARSE_ERROR; - } - } else { - _set_error("Expected single integer constant > 0"); - return ERR_PARSE_ERROR; + if (tk.type == TK_BRACKET_OPEN) { + Error error = _parse_global_array_size(member->array_size); + if (error != OK) { + return error; } + tk = _get_token(); } - st_node->members.push_back(member); if (tk.type != TK_SEMICOLON) { - _set_error("Expected ']' or ';'"); + _set_error("Expected ';'"); return ERR_PARSE_ERROR; } + + st_node->members.push_back(member); member_count++; } } @@ -6886,12 +7647,13 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct bool uniform = tk.type == TK_UNIFORM; if (!uniform) { - if (shader_type_identifier == "particles" || shader_type_identifier == "sky") { + if (shader_type_identifier == "particles" || shader_type_identifier == "sky" || shader_type_identifier == "fog") { _set_error(vformat("Varyings cannot be used in '%s' shaders!", shader_type_identifier)); return ERR_PARSE_ERROR; } } + bool precision_defined = false; DataPrecision precision = PRECISION_DEFAULT; DataInterpolation interpolation = INTERPOLATION_SMOOTH; DataType type; @@ -6900,15 +7662,34 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (is_token_interpolation(tk.type)) { + if (uniform) { + _set_error("Interpolation qualifiers are not supported for uniforms!"); + return ERR_PARSE_ERROR; + } interpolation = get_token_interpolation(tk.type); tk = _get_token(); } if (is_token_precision(tk.type)) { precision = get_token_precision(tk.type); + precision_defined = true; tk = _get_token(); } + if (shader->structs.has(tk.text)) { + if (uniform) { + if (precision_defined) { + _set_error("Precision modifier cannot be used on structs."); + return ERR_PARSE_ERROR; + } + _set_error("struct datatype is not yet supported for uniforms!"); + return ERR_PARSE_ERROR; + } else { + _set_error("struct datatype not allowed here"); + return ERR_PARSE_ERROR; + } + } + if (!is_token_datatype(tk.type)) { _set_error("Expected datatype. "); return ERR_PARSE_ERROR; @@ -6928,27 +7709,17 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); + if (tk.type != TK_IDENTIFIER && tk.type != TK_BRACKET_OPEN) { + _set_error("Expected identifier or '['."); + return ERR_PARSE_ERROR; + } + if (tk.type == TK_BRACKET_OPEN) { - if (uniform) { - _set_error(vformat("Uniform arrays are not yet implemented!")); - return ERR_PARSE_ERROR; + Error error = _parse_global_array_size(array_size); + if (error != OK) { + return error; } tk = _get_token(); - - if (tk.type == TK_INT_CONSTANT && tk.constant > 0) { - array_size = (int)tk.constant; - - tk = _get_token(); - if (tk.type == TK_BRACKET_CLOSE) { - tk = _get_token(); - } else { - _set_error("Expected ']'"); - return ERR_PARSE_ERROR; - } - } else { - _set_error("Expected integer constant > 0"); - return ERR_PARSE_ERROR; - } } if (tk.type != TK_IDENTIFIER) { @@ -6985,12 +7756,32 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } ShaderNode::Uniform uniform2; + uniform2.type = type; + uniform2.scope = uniform_scope; + uniform2.precision = precision; + uniform2.array_size = array_size; + + tk = _get_token(); + if (tk.type == TK_BRACKET_OPEN) { + Error error = _parse_global_array_size(uniform2.array_size); + if (error != OK) { + return error; + } + tk = _get_token(); + } + if (is_sampler_type(type)) { if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) { _set_error("Uniforms with 'instance' qualifiers can't be of sampler type."); return ERR_PARSE_ERROR; } uniform2.texture_order = texture_uniforms++; + uniform2.texture_binding = texture_binding; + if (uniform2.array_size > 0) { + texture_binding += uniform2.array_size; + } else { + ++texture_binding; + } uniform2.order = -1; if (_validate_datatype(type) != OK) { return ERR_PARSE_ERROR; @@ -7000,19 +7791,22 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct _set_error("Uniforms with 'instance' qualifiers can't be of matrix type."); return ERR_PARSE_ERROR; } - uniform2.texture_order = -1; if (uniform_scope != ShaderNode::Uniform::SCOPE_INSTANCE) { uniform2.order = uniforms++; } } - uniform2.type = type; - uniform2.scope = uniform_scope; - uniform2.precision = precision; - - //todo parse default value - tk = _get_token(); + if (uniform2.array_size > 0) { + if (uniform_scope == ShaderNode::Uniform::SCOPE_GLOBAL) { + _set_error("'SCOPE_GLOBAL' qualifier is not yet supported for uniform array!"); + return ERR_PARSE_ERROR; + } + if (uniform_scope == ShaderNode::Uniform::SCOPE_INSTANCE) { + _set_error("'SCOPE_INSTANCE' qualifier is not yet supported for uniform array!"); + return ERR_PARSE_ERROR; + } + } int custom_instance_index = -1; @@ -7020,6 +7814,14 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct //hint do { tk = _get_token(); + + if (uniform2.array_size > 0) { + if (tk.type != TK_HINT_COLOR) { + _set_error("This hint is not yet supported for uniform arrays!"); + return ERR_PARSE_ERROR; + } + } + if (tk.type == TK_HINT_WHITE_TEXTURE) { uniform2.hint = ShaderNode::Uniform::HINT_WHITE; } else if (tk.type == TK_HINT_BLACK_TEXTURE) { @@ -7210,6 +8012,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct //reset scope for next uniform if (tk.type == TK_OP_ASSIGN) { + if (uniform2.array_size > 0) { + _set_error("Setting default value to a uniform array is not yet supported!"); + return ERR_PARSE_ERROR; + } + Node *expr = _parse_and_reduce_expression(nullptr, FunctionInfo()); if (!expr) { return ERR_PARSE_ERROR; @@ -7254,7 +8061,11 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct tk = _get_token(); if (tk.type != TK_SEMICOLON && tk.type != TK_BRACKET_OPEN) { - _set_error("Expected ';' or '['"); + if (array_size == 0) { + _set_error("Expected ';' or '['"); + } else { + _set_error("Expected ';'"); + } return ERR_PARSE_ERROR; } @@ -7279,7 +8090,7 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return ERR_PARSE_ERROR; } } else { - _set_error("Expected single integer constant > 0"); + _set_error("Expected integer constant > 0"); return ERR_PARSE_ERROR; } } @@ -7701,8 +8512,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } if (p_functions.has("global")) { // Adds global variables: 'TIME' - for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) { - builtins.built_ins.insert(E->key(), E->value()); + for (const KeyValue<StringName, BuiltInInfo> &E : p_functions["global"].built_ins) { + builtins.built_ins.insert(E.key, E.value); } } @@ -7974,8 +8785,8 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct } bool ShaderLanguage::has_builtin(const Map<StringName, ShaderLanguage::FunctionInfo> &p_functions, const StringName &p_name) { - for (Map<StringName, ShaderLanguage::FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) { - if (E->get().built_ins.has(p_name)) { + for (const KeyValue<StringName, ShaderLanguage::FunctionInfo> &E : p_functions) { + if (E.value.built_ins.has(p_name)) { return true; } } @@ -8115,19 +8926,19 @@ String ShaderLanguage::get_shader_type(const String &p_code) { #ifdef DEBUG_ENABLED void ShaderLanguage::_check_warning_accums() { - for (Map<ShaderWarning::Code, Map<StringName, Map<StringName, Usage>> *>::Element *E = warnings_check_map2.front(); E; E = E->next()) { - for (Map<StringName, Map<StringName, Usage>>::Element *T = (*E->get()).front(); T; T = T->next()) { - for (const Map<StringName, Usage>::Element *U = T->get().front(); U; U = U->next()) { - if (!U->get().used) { - _add_warning(E->key(), U->get().decl_line, U->key()); + for (const KeyValue<ShaderWarning::Code, Map<StringName, Map<StringName, Usage>> *> &E : warnings_check_map2) { + for (Map<StringName, Map<StringName, Usage>>::Element *T = (*E.value).front(); T; T = T->next()) { + for (const KeyValue<StringName, Usage> &U : T->get()) { + if (!U.value.used) { + _add_warning(E.key, U.value.decl_line, U.key); } } } } - for (Map<ShaderWarning::Code, Map<StringName, Usage> *>::Element *E = warnings_check_map.front(); E; E = E->next()) { - for (const Map<StringName, Usage>::Element *U = (*E->get()).front(); U; U = U->next()) { + for (const KeyValue<ShaderWarning::Code, Map<StringName, Usage> *> &E : warnings_check_map) { + for (const Map<StringName, Usage>::Element *U = (*E.value).front(); U; U = U->next()) { if (!U->get().used) { - _add_warning(E->key(), U->get().decl_line, U->key()); + _add_warning(E.key, U->get().decl_line, U->key()); } } } @@ -8210,8 +9021,8 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct return OK; } break; case COMPLETION_MAIN_FUNCTION: { - for (const Map<StringName, FunctionInfo>::Element *E = p_functions.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->key(), ScriptCodeCompletionOption::KIND_FUNCTION); + for (const KeyValue<StringName, FunctionInfo> &E : p_functions) { + ScriptCodeCompletionOption option(E.key, ScriptCodeCompletionOption::KIND_FUNCTION); r_options->push_back(option); } @@ -8227,9 +9038,9 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct if (completion_class == TAG_GLOBAL) { while (block) { if (comp_ident) { - for (const Map<StringName, BlockNode::Variable>::Element *E = block->variables.front(); E; E = E->next()) { - if (E->get().line < completion_line) { - matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE); + for (const KeyValue<StringName, BlockNode::Variable> &E : block->variables) { + if (E.value.line < completion_line) { + matches.insert(E.key, ScriptCodeCompletionOption::KIND_VARIABLE); } } } @@ -8247,30 +9058,30 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct if (comp_ident) { if (p_functions.has("global")) { - for (Map<StringName, BuiltInInfo>::Element *E = p_functions["global"].built_ins.front(); E; E = E->next()) { + for (const KeyValue<StringName, BuiltInInfo> &E : p_functions["global"].built_ins) { ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER; - if (E->get().constant) { + if (E.value.constant) { kind = ScriptCodeCompletionOption::KIND_CONSTANT; } - matches.insert(E->key(), kind); + matches.insert(E.key, kind); } } if (skip_function != StringName() && p_functions.has(skip_function)) { - for (Map<StringName, BuiltInInfo>::Element *E = p_functions[skip_function].built_ins.front(); E; E = E->next()) { + for (const KeyValue<StringName, BuiltInInfo> &E : p_functions[skip_function].built_ins) { ScriptCodeCompletionOption::Kind kind = ScriptCodeCompletionOption::KIND_MEMBER; - if (E->get().constant) { + if (E.value.constant) { kind = ScriptCodeCompletionOption::KIND_CONSTANT; } - matches.insert(E->key(), kind); + matches.insert(E.key, kind); } } - for (const Map<StringName, ShaderNode::Varying>::Element *E = shader->varyings.front(); E; E = E->next()) { - matches.insert(E->key(), ScriptCodeCompletionOption::KIND_VARIABLE); + for (const KeyValue<StringName, ShaderNode::Varying> &E : shader->varyings) { + matches.insert(E.key, ScriptCodeCompletionOption::KIND_VARIABLE); } - for (const Map<StringName, ShaderNode::Uniform>::Element *E = shader->uniforms.front(); E; E = E->next()) { - matches.insert(E->key(), ScriptCodeCompletionOption::KIND_MEMBER); + for (const KeyValue<StringName, ShaderNode::Uniform> &E : shader->uniforms) { + matches.insert(E.key, ScriptCodeCompletionOption::KIND_MEMBER); } } @@ -8285,8 +9096,8 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct bool low_end = RenderingServer::get_singleton()->is_low_end(); if (stages && stages->has(skip_function)) { - for (const Map<StringName, StageFunctionInfo>::Element *E = (*stages)[skip_function].stage_functions.front(); E; E = E->next()) { - matches.insert(String(E->key()), ScriptCodeCompletionOption::KIND_FUNCTION); + for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[skip_function].stage_functions) { + matches.insert(String(E.key), ScriptCodeCompletionOption::KIND_FUNCTION); } } @@ -8315,9 +9126,9 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } } - for (Map<String, ScriptCodeCompletionOption::Kind>::Element *E = matches.front(); E; E = E->next()) { - ScriptCodeCompletionOption option(E->key(), E->value()); - if (E->value() == ScriptCodeCompletionOption::KIND_FUNCTION) { + for (const KeyValue<String, ScriptCodeCompletionOption::Kind> &E : matches) { + ScriptCodeCompletionOption option(E.key, E.value); + if (E.value == ScriptCodeCompletionOption::KIND_FUNCTION) { option.insert_text += "("; } r_options->push_back(option); @@ -8409,14 +9220,14 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct bool low_end = RenderingServer::get_singleton()->is_low_end(); if (stages && stages->has(block_function)) { - for (const Map<StringName, StageFunctionInfo>::Element *E = (*stages)[block_function].stage_functions.front(); E; E = E->next()) { - if (completion_function == E->key()) { - calltip += get_datatype_name(E->get().return_type); + for (const KeyValue<StringName, StageFunctionInfo> &E : (*stages)[block_function].stage_functions) { + if (completion_function == E.key) { + calltip += get_datatype_name(E.value.return_type); calltip += " "; - calltip += E->key(); + calltip += E.key; calltip += "("; - for (int i = 0; i < E->get().arguments.size(); i++) { + for (int i = 0; i < E.value.arguments.size(); i++) { if (i > 0) { calltip += ", "; } else { @@ -8427,16 +9238,16 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct calltip += char32_t(0xFFFF); } - calltip += get_datatype_name(E->get().arguments[i].type); + calltip += get_datatype_name(E.value.arguments[i].type); calltip += " "; - calltip += E->get().arguments[i].name; + calltip += E.value.arguments[i].name; if (i == completion_argument) { calltip += char32_t(0xFFFF); } } - if (E->get().arguments.size()) { + if (E.value.arguments.size()) { calltip += " "; } calltip += ")"; @@ -8454,10 +9265,16 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct } int idx2 = 0; - int out_arg = -1; + Set<int> out_args; while (builtin_func_out_args[idx2].name != nullptr) { if (builtin_func_out_args[idx2].name == builtin_func_defs[idx].name) { - out_arg = builtin_func_out_args[idx2].argument; + for (int i = 0; i < BuiltinFuncOutArgs::MAX_ARGS; i++) { + int arg = builtin_func_out_args[idx2].arguments[i]; + if (arg == -1) { + break; + } + out_args.insert(arg); + } break; } idx2++; @@ -8494,7 +9311,7 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct calltip += char32_t(0xFFFF); } - if (out_arg >= 0 && i == out_arg) { + if (out_args.has(i)) { calltip += "out "; } @@ -8555,15 +9372,6 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct limit = 4; } break; - case TYPE_MAT2: - limit = 2; - break; - case TYPE_MAT3: - limit = 3; - break; - case TYPE_MAT4: - limit = 4; - break; default: { } } diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 18525e054e..c82f71d10d 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -692,8 +692,10 @@ public: int order = 0; int texture_order = 0; + int texture_binding = 0; DataType type = TYPE_VOID; DataPrecision precision = PRECISION_DEFAULT; + int array_size = 0; Vector<ConstantNode::Value> default_value; Scope scope = SCOPE_LOCAL; Hint hint = HINT_NONE; @@ -776,7 +778,7 @@ public: static bool is_scalar_type(DataType p_type); static bool is_float_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, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE); + static Variant constant_value_to_variant(const Vector<ShaderLanguage::ConstantNode::Value> &p_value, DataType p_type, int p_array_size, ShaderLanguage::ShaderNode::Uniform::Hint p_hint = ShaderLanguage::ShaderNode::Uniform::HINT_NONE); static PropertyInfo uniform_to_property_info(const ShaderNode::Uniform &p_uniform); static uint32_t get_type_size(DataType p_type); @@ -874,7 +876,6 @@ private: StringName current_function; bool last_const = false; - bool pass_array = false; StringName last_name; VaryingFunctionNames varying_function_names; @@ -948,8 +949,16 @@ private: }; struct BuiltinFuncOutArgs { //arguments used as out in built in functions + enum { MAX_ARGS = 2 }; const char *name; - int argument; + const int arguments[MAX_ARGS]; + }; + + struct BuiltinFuncConstArgs { + const char *name; + int arg; + int min; + int max; }; CompletionType completion_type; @@ -965,6 +974,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[]; + static const BuiltinFuncConstArgs builtin_func_const_args[]; Error _validate_datatype(DataType p_type); bool _compare_datatypes(DataType p_datatype_a, String p_datatype_name_a, int p_array_size_a, DataType p_datatype_b, String p_datatype_name_b, int p_array_size_b); @@ -978,6 +988,10 @@ private: bool _validate_varying_using(ShaderNode::Varying &p_varying, String *r_message); bool _check_node_constness(const Node *p_node) const; + Node *_parse_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, int &r_array_size); + Error _parse_global_array_size(int &r_array_size); + Error _parse_local_array_size(BlockNode *p_block, const FunctionInfo &p_function_info, ArrayDeclarationNode *p_node, ArrayDeclarationNode::Declaration *p_decl, int &r_array_size, bool &r_is_unknown_size); + Node *_parse_expression(BlockNode *p_block, const FunctionInfo &p_function_info); Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info); Node *_parse_array_constructor(BlockNode *p_block, const FunctionInfo &p_function_info, DataType p_type, const StringName &p_struct_name, int p_array_size); diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp index 0bfcccef28..eb5c9e66e8 100644 --- a/servers/rendering/shader_types.cpp +++ b/servers/rendering/shader_types.cpp @@ -443,10 +443,29 @@ ShaderTypes::ShaderTypes() { shader_modes[RS::SHADER_SKY].modes.push_back("use_quarter_res_pass"); shader_modes[RS::SHADER_SKY].modes.push_back("disable_fog"); + /************ FOG **************************/ + + shader_modes[RS::SHADER_FOG].functions["global"].built_ins["TIME"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_FOG].functions["global"].built_ins["PI"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_FOG].functions["global"].built_ins["TAU"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_FOG].functions["global"].built_ins["E"] = constt(ShaderLanguage::TYPE_FLOAT); + + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["WORLD_POSITION"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["OBJECT_POSITION"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["UVW"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EXTENTS"] = constt(ShaderLanguage::TYPE_VEC3); + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["TRANSFORM"] = constt(ShaderLanguage::TYPE_MAT4); + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["SDF"] = constt(ShaderLanguage::TYPE_FLOAT); + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["ALBEDO"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["DENSITY"] = ShaderLanguage::TYPE_FLOAT; + shader_modes[RS::SHADER_FOG].functions["fog"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3; + shader_modes[RS::SHADER_FOG].functions["fog"].main_function = true; + shader_types_list.push_back("spatial"); shader_types_list.push_back("canvas_item"); shader_types_list.push_back("particles"); shader_types_list.push_back("sky"); + shader_types_list.push_back("fog"); for (int i = 0; i < shader_types_list.size(); i++) { shader_types.insert(shader_types_list[i]); diff --git a/servers/rendering/shader_warnings.cpp b/servers/rendering/shader_warnings.cpp index 0c1d6408c9..0b8476478c 100644 --- a/servers/rendering/shader_warnings.cpp +++ b/servers/rendering/shader_warnings.cpp @@ -119,10 +119,10 @@ ShaderWarning::CodeFlags ShaderWarning::get_flags_from_codemap(const Map<Code, b init_code_to_flags_map(); } - for (Map<Code, bool>::Element *E = p_map.front(); E; E = E->next()) { - if (E->get()) { - ERR_FAIL_COND_V(!code_to_flags_map->has((int)E->key()), ShaderWarning::NONE_FLAG); - result |= (*code_to_flags_map)[(int)E->key()]; + for (const KeyValue<Code, bool> &E : p_map) { + if (E.value) { + ERR_FAIL_COND_V(!code_to_flags_map->has((int)E.key), ShaderWarning::NONE_FLAG); + result |= (*code_to_flags_map)[(int)E.key]; } } return (CodeFlags)result; diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index 78604dfe8c..7a958546b6 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -500,7 +500,7 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint case RS::ARRAY_CUSTOM1: case RS::ARRAY_CUSTOM2: case RS::ARRAY_CUSTOM3: { - uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - ai))) & ARRAY_FORMAT_CUSTOM_MASK; + uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (ai - RS::ARRAY_CUSTOM0))) & ARRAY_FORMAT_CUSTOM_MASK; switch (type) { case ARRAY_CUSTOM_RGBA8_UNORM: case ARRAY_CUSTOM_RGBA8_SNORM: @@ -541,14 +541,14 @@ Error RenderingServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint ERR_FAIL_COND_V(p_arrays[ai].get_type() != Variant::PACKED_FLOAT32_ARRAY, ERR_INVALID_PARAMETER); Vector<float> array = p_arrays[ai]; - int32_t s = ARRAY_CUSTOM_R_FLOAT - ai + 1; + int32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1; ERR_FAIL_COND_V(array.size() != p_vertex_array_len * s, ERR_INVALID_PARAMETER); const float *src = array.ptr(); for (int i = 0; i < p_vertex_array_len; i++) { - memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], 4 * s); + memcpy(&aw[p_offsets[ai] + i * p_attrib_stride], &src[i * s], sizeof(float) * s); } } break; default: { @@ -934,7 +934,14 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa } } - ERR_FAIL_COND_V((bsformat) != (format & (RS::ARRAY_FORMAT_INDEX - 1)), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG((bsformat & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK) != (format & RS::ARRAY_FORMAT_BLEND_SHAPE_MASK), ERR_INVALID_PARAMETER, "Blend shape format must match the main array format for Vertex, Normal and Tangent arrays."); + } + } + + for (uint32_t i = 0; i < RS::ARRAY_CUSTOM_COUNT; ++i) { + // include custom array format type. + if (format & (1 << (ARRAY_CUSTOM0 + i))) { + format |= (RS::ARRAY_FORMAT_CUSTOM_MASK << (RS::ARRAY_FORMAT_CUSTOM_BASE + i * RS::ARRAY_FORMAT_CUSTOM_BITS)) & p_compress_format; } } @@ -1191,7 +1198,7 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t case RS::ARRAY_CUSTOM1: case RS::ARRAY_CUSTOM2: case RS::ARRAY_CUSTOM3: { - uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (RS::ARRAY_CUSTOM0 - i))) & ARRAY_FORMAT_CUSTOM_MASK; + uint32_t type = (p_format >> (ARRAY_FORMAT_CUSTOM_BASE + ARRAY_FORMAT_CUSTOM_BITS * (i - RS::ARRAY_CUSTOM0))) & ARRAY_FORMAT_CUSTOM_MASK; switch (type) { case ARRAY_CUSTOM_RGBA8_UNORM: case ARRAY_CUSTOM_RGBA8_SNORM: @@ -1219,6 +1226,8 @@ Array RenderingServer::_get_array_from_surface(uint32_t p_format, Vector<uint8_t uint32_t s = type - ARRAY_CUSTOM_R_FLOAT + 1; Vector<float> arr; + arr.resize(s * p_vertex_len); + float *w = arr.ptrw(); for (int j = 0; j < p_vertex_len; j++) { @@ -1467,6 +1476,11 @@ ShaderLanguage::DataType RenderingServer::global_variable_type_get_shader_dataty } } +RenderingDevice *RenderingServer::get_rendering_device() const { + // return the rendering device we're using globally + return RenderingDevice::get_singleton(); +} + RenderingDevice *RenderingServer::create_local_rendering_device() const { return RenderingDevice::get_singleton()->create_local_device(); } @@ -1702,13 +1716,14 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shader_get_param_list", "shader"), &RenderingServer::_shader_get_param_list); ClassDB::bind_method(D_METHOD("shader_get_param_default", "shader", "param"), &RenderingServer::shader_get_param_default); - ClassDB::bind_method(D_METHOD("shader_set_default_texture_param", "shader", "param", "texture"), &RenderingServer::shader_set_default_texture_param); - ClassDB::bind_method(D_METHOD("shader_get_default_texture_param", "shader", "param"), &RenderingServer::shader_get_default_texture_param); + ClassDB::bind_method(D_METHOD("shader_set_default_texture_param", "shader", "param", "texture", "index"), &RenderingServer::shader_set_default_texture_param, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("shader_get_default_texture_param", "shader", "param", "index"), &RenderingServer::shader_get_default_texture_param, DEFVAL(0)); BIND_ENUM_CONSTANT(SHADER_SPATIAL); BIND_ENUM_CONSTANT(SHADER_CANVAS_ITEM); BIND_ENUM_CONSTANT(SHADER_PARTICLES); BIND_ENUM_CONSTANT(SHADER_SKY); + BIND_ENUM_CONSTANT(SHADER_FOG); BIND_ENUM_CONSTANT(SHADER_MAX); /* MATERIAL */ @@ -1928,6 +1943,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("directional_shadow_atlas_set_size", "size", "is_16bits"), &RenderingServer::directional_shadow_atlas_set_size); BIND_ENUM_CONSTANT(SHADOW_QUALITY_HARD); + BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_VERY_LOW); BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_LOW); BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_MEDIUM); BIND_ENUM_CONSTANT(SHADOW_QUALITY_SOFT_HIGH); @@ -2111,6 +2127,17 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_8192); BIND_ENUM_CONSTANT(PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX); + /* FOG VOLUMES */ + + ClassDB::bind_method(D_METHOD("fog_volume_create"), &RenderingServer::fog_volume_create); + ClassDB::bind_method(D_METHOD("fog_volume_set_shape", "fog_volume", "shape"), &RenderingServer::fog_volume_set_shape); + ClassDB::bind_method(D_METHOD("fog_volume_set_extents", "fog_volume", "extents"), &RenderingServer::fog_volume_set_extents); + ClassDB::bind_method(D_METHOD("fog_volume_set_material", "fog_volume", "material"), &RenderingServer::fog_volume_set_material); + + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_ELLIPSOID); + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_BOX); + BIND_ENUM_CONSTANT(FOG_VOLUME_SHAPE_WORLD); + /* VISIBILITY NOTIFIER */ ClassDB::bind_method(D_METHOD("visibility_notifier_create"), &RenderingServer::visibility_notifier_create); @@ -2138,13 +2165,16 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_create"), &RenderingServer::viewport_create); ClassDB::bind_method(D_METHOD("viewport_set_use_xr", "viewport", "use_xr"), &RenderingServer::viewport_set_use_xr); - ClassDB::bind_method(D_METHOD("viewport_set_scale_3d", "viewport", "scale"), &RenderingServer::viewport_set_scale_3d); ClassDB::bind_method(D_METHOD("viewport_set_size", "viewport", "width", "height"), &RenderingServer::viewport_set_size); ClassDB::bind_method(D_METHOD("viewport_set_active", "viewport", "active"), &RenderingServer::viewport_set_active); ClassDB::bind_method(D_METHOD("viewport_set_parent_viewport", "viewport", "parent_viewport"), &RenderingServer::viewport_set_parent_viewport); ClassDB::bind_method(D_METHOD("viewport_attach_to_screen", "viewport", "rect", "screen"), &RenderingServer::viewport_attach_to_screen, DEFVAL(Rect2()), DEFVAL(DisplayServer::MAIN_WINDOW_ID)); ClassDB::bind_method(D_METHOD("viewport_set_render_direct_to_screen", "viewport", "enabled"), &RenderingServer::viewport_set_render_direct_to_screen); + ClassDB::bind_method(D_METHOD("viewport_set_scaling_3d_mode", "viewport", "scaling_3d_mode"), &RenderingServer::viewport_set_scaling_3d_mode); + ClassDB::bind_method(D_METHOD("viewport_set_scaling_3d_scale", "viewport", "scale"), &RenderingServer::viewport_set_scaling_3d_scale); + ClassDB::bind_method(D_METHOD("viewport_set_fsr_sharpness", "viewport", "sharpness"), &RenderingServer::viewport_set_fsr_sharpness); + ClassDB::bind_method(D_METHOD("viewport_set_fsr_mipmap_bias", "viewport", "mipmap_bias"), &RenderingServer::viewport_set_fsr_mipmap_bias); ClassDB::bind_method(D_METHOD("viewport_set_update_mode", "viewport", "update_mode"), &RenderingServer::viewport_set_update_mode); ClassDB::bind_method(D_METHOD("viewport_set_clear_mode", "viewport", "clear_mode"), &RenderingServer::viewport_set_clear_mode); ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &RenderingServer::viewport_get_texture); @@ -2186,6 +2216,10 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_get_measured_render_time_gpu", "viewport"), &RenderingServer::viewport_get_measured_render_time_gpu); + BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_BILINEAR); + BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_FSR); + BIND_ENUM_CONSTANT(VIEWPORT_SCALING_3D_MODE_MAX); + BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_DISABLED); BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_ONCE); //then goes to disabled); must be manually updated BIND_ENUM_CONSTANT(VIEWPORT_UPDATE_WHEN_VISIBLE); // default @@ -2211,7 +2245,6 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_MSAA_2X); BIND_ENUM_CONSTANT(VIEWPORT_MSAA_4X); BIND_ENUM_CONSTANT(VIEWPORT_MSAA_8X); - BIND_ENUM_CONSTANT(VIEWPORT_MSAA_16X); BIND_ENUM_CONSTANT(VIEWPORT_MSAA_MAX); BIND_ENUM_CONSTANT(VIEWPORT_SCREEN_SPACE_AA_DISABLED); @@ -2256,12 +2289,6 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_CLUSTER_REFLECTION_PROBES); BIND_ENUM_CONSTANT(VIEWPORT_DEBUG_DRAW_OCCLUDERS); - BIND_ENUM_CONSTANT(VIEWPORT_SCALE_3D_DISABLED); - BIND_ENUM_CONSTANT(VIEWPORT_SCALE_3D_75_PERCENT); - BIND_ENUM_CONSTANT(VIEWPORT_SCALE_3D_50_PERCENT); - BIND_ENUM_CONSTANT(VIEWPORT_SCALE_3D_33_PERCENT); - BIND_ENUM_CONSTANT(VIEWPORT_SCALE_3D_25_PERCENT); - /* SKY API */ ClassDB::bind_method(D_METHOD("sky_create"), &RenderingServer::sky_create); @@ -2285,7 +2312,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_bg_color", "env", "color"), &RenderingServer::environment_set_bg_color); ClassDB::bind_method(D_METHOD("environment_set_bg_energy", "env", "energy"), &RenderingServer::environment_set_bg_energy); ClassDB::bind_method(D_METHOD("environment_set_canvas_max_layer", "env", "max_layer"), &RenderingServer::environment_set_canvas_max_layer); - ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source", "ao_color"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG), DEFVAL(Color())); + ClassDB::bind_method(D_METHOD("environment_set_ambient_light", "env", "color", "ambient", "energy", "sky_contibution", "reflection_source"), &RenderingServer::environment_set_ambient_light, DEFVAL(RS::ENV_AMBIENT_SOURCE_BG), DEFVAL(1.0), DEFVAL(0.0), DEFVAL(RS::ENV_REFLECTION_SOURCE_BG)); ClassDB::bind_method(D_METHOD("environment_set_glow", "env", "enable", "levels", "intensity", "strength", "mix", "bloom_threshold", "blend_mode", "hdr_bleed_threshold", "hdr_bleed_scale", "hdr_luminance_cap"), &RenderingServer::environment_set_glow); ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &RenderingServer::environment_set_tonemap); ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "use_1d_color_correction", "color_correction"), &RenderingServer::environment_set_adjustment); @@ -2293,7 +2320,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "power", "detail", "horizon", "sharpness", "light_affect", "ao_channel_affect"), &RenderingServer::environment_set_ssao); ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "light_color", "light_energy", "sun_scatter", "density", "height", "height_density", "aerial_perspective"), &RenderingServer::environment_set_fog); ClassDB::bind_method(D_METHOD("environment_set_sdfgi", "env", "enable", "cascades", "min_cell_size", "y_scale", "use_occlusion", "bounce_feedback", "read_sky", "energy", "normal_bias", "probe_bias"), &RenderingServer::environment_set_sdfgi); - ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "light", "light_energy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount"), &RenderingServer::environment_set_volumetric_fog); + ClassDB::bind_method(D_METHOD("environment_set_volumetric_fog", "env", "enable", "density", "albedo", "emission", "emission_energy", "anisotropy", "length", "p_detail_spread", "gi_inject", "temporal_reprojection", "temporal_reprojection_amount", "ambient_inject"), &RenderingServer::environment_set_volumetric_fog); ClassDB::bind_method(D_METHOD("environment_glow_set_use_bicubic_upscale", "enable"), &RenderingServer::environment_glow_set_use_bicubic_upscale); ClassDB::bind_method(D_METHOD("environment_glow_set_use_high_quality", "enable"), &RenderingServer::environment_glow_set_use_high_quality); @@ -2425,17 +2452,19 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("instance_set_blend_shape_weight", "instance", "shape", "weight"), &RenderingServer::instance_set_blend_shape_weight); ClassDB::bind_method(D_METHOD("instance_set_surface_override_material", "instance", "surface", "material"), &RenderingServer::instance_set_surface_override_material); ClassDB::bind_method(D_METHOD("instance_set_visible", "instance", "visible"), &RenderingServer::instance_set_visible); + ClassDB::bind_method(D_METHOD("instance_geometry_set_transparency", "instance", "transparency"), &RenderingServer::instance_geometry_set_transparency); ClassDB::bind_method(D_METHOD("instance_set_custom_aabb", "instance", "aabb"), &RenderingServer::instance_set_custom_aabb); ClassDB::bind_method(D_METHOD("instance_attach_skeleton", "instance", "skeleton"), &RenderingServer::instance_attach_skeleton); ClassDB::bind_method(D_METHOD("instance_set_extra_visibility_margin", "instance", "margin"), &RenderingServer::instance_set_extra_visibility_margin); ClassDB::bind_method(D_METHOD("instance_set_visibility_parent", "instance", "parent"), &RenderingServer::instance_set_visibility_parent); + ClassDB::bind_method(D_METHOD("instance_set_ignore_culling", "instance", "enabled"), &RenderingServer::instance_set_ignore_culling); ClassDB::bind_method(D_METHOD("instance_geometry_set_flag", "instance", "flag", "enabled"), &RenderingServer::instance_geometry_set_flag); ClassDB::bind_method(D_METHOD("instance_geometry_set_cast_shadows_setting", "instance", "shadow_casting_setting"), &RenderingServer::instance_geometry_set_cast_shadows_setting); ClassDB::bind_method(D_METHOD("instance_geometry_set_material_override", "instance", "material"), &RenderingServer::instance_geometry_set_material_override); - ClassDB::bind_method(D_METHOD("instance_geometry_set_visibility_range", "instance", "min", "max", "min_margin", "max_margin"), &RenderingServer::instance_geometry_set_visibility_range); + ClassDB::bind_method(D_METHOD("instance_geometry_set_visibility_range", "instance", "min", "max", "min_margin", "max_margin", "fade_mode"), &RenderingServer::instance_geometry_set_visibility_range); ClassDB::bind_method(D_METHOD("instance_geometry_set_lightmap", "instance", "lightmap", "lightmap_uv_scale", "lightmap_slice"), &RenderingServer::instance_geometry_set_lightmap); ClassDB::bind_method(D_METHOD("instance_geometry_set_lod_bias", "instance", "lod_bias"), &RenderingServer::instance_geometry_set_lod_bias); @@ -2460,6 +2489,7 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(INSTANCE_LIGHTMAP); BIND_ENUM_CONSTANT(INSTANCE_OCCLUDER); BIND_ENUM_CONSTANT(INSTANCE_VISIBLITY_NOTIFIER); + BIND_ENUM_CONSTANT(INSTANCE_FOG_VOLUME); BIND_ENUM_CONSTANT(INSTANCE_MAX); BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK); @@ -2475,6 +2505,10 @@ void RenderingServer::_bind_methods() { BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_DOUBLE_SIDED); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_SHADOWS_ONLY); + BIND_ENUM_CONSTANT(VISIBILITY_RANGE_FADE_DISABLED); + BIND_ENUM_CONSTANT(VISIBILITY_RANGE_FADE_SELF); + BIND_ENUM_CONSTANT(VISIBILITY_RANGE_FADE_DEPENDENCIES); + /* Bake 3D Object */ ClassDB::bind_method(D_METHOD("bake_render_uv2", "base", "material_overrides", "image_size"), &RenderingServer::bake_render_uv2); @@ -2526,6 +2560,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect); ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false)); + ClassDB::bind_method(D_METHOD("canvas_item_add_msdf_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "outline_size", "px_range"), &RenderingServer::canvas_item_add_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(0), DEFVAL(1.0)); ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true)); ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0)); @@ -2673,7 +2708,7 @@ void RenderingServer::_bind_methods() { /* Misc */ - ClassDB::bind_method(D_METHOD("request_frame_drawn_callback", "where", "method", "userdata"), &RenderingServer::request_frame_drawn_callback); + ClassDB::bind_method(D_METHOD("request_frame_drawn_callback", "callable"), &RenderingServer::request_frame_drawn_callback); ClassDB::bind_method(D_METHOD("has_changed"), &RenderingServer::has_changed); ClassDB::bind_method(D_METHOD("get_rendering_info", "info"), &RenderingServer::get_rendering_info); ClassDB::bind_method(D_METHOD("get_video_adapter_name"), &RenderingServer::get_video_adapter_name); @@ -2714,6 +2749,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("force_sync"), &RenderingServer::sync); ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &RenderingServer::draw, DEFVAL(true), DEFVAL(0.0)); + ClassDB::bind_method(D_METHOD("get_rendering_device"), &RenderingServer::get_rendering_device); ClassDB::bind_method(D_METHOD("create_local_rendering_device"), &RenderingServer::create_local_rendering_device); } @@ -2784,14 +2820,14 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/shadows/directional_shadow/size", 4096); GLOBAL_DEF("rendering/shadows/directional_shadow/size.mobile", 2048); ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/size", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/size", PROPERTY_HINT_RANGE, "256,16384")); - GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality", 2); + GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality", 3); GLOBAL_DEF("rendering/shadows/directional_shadow/soft_shadow_quality.mobile", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/directional_shadow/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/directional_shadow/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); GLOBAL_DEF("rendering/shadows/directional_shadow/16_bits", true); - GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality", 2); + GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality", 3); GLOBAL_DEF("rendering/shadows/shadows/soft_shadow_quality.mobile", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadows/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/shadows/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/shadows/shadows/soft_shadow_quality", PropertyInfo(Variant::INT, "rendering/shadows/shadows/soft_shadow_quality", PROPERTY_HINT_ENUM, "Hard (Fastest),Soft Very Low (Faster),Soft Low (Fast),Soft Medium (Average),Soft High (Slow),Soft Ultra (Slowest)")); GLOBAL_DEF("rendering/2d/shadow_atlas/size", 2048); @@ -2801,12 +2837,12 @@ RenderingServer::RenderingServer() { PropertyInfo(Variant::INT, "rendering/vulkan/rendering/back_end", PROPERTY_HINT_ENUM, "Forward Clustered (Supports Desktop Only),Forward Mobile (Supports Desktop and Mobile)")); - - GLOBAL_DEF("rendering/3d/viewport/scale", 0); - ProjectSettings::get_singleton()->set_custom_property_info("rendering/3d/viewport/scale", - PropertyInfo(Variant::INT, - "rendering/3d/viewport/scale", - PROPERTY_HINT_ENUM, "Disabled,75%,50%,33%,25%")); + // Already defined in RenderingDeviceVulkan::initialize which runs before this code. + // We re-define them here just for doctool's sake. Make sure to keep default values in sync. + GLOBAL_DEF("rendering/vulkan/staging_buffer/block_size_kb", 256); + GLOBAL_DEF("rendering/vulkan/staging_buffer/max_size_mb", 128); + GLOBAL_DEF("rendering/vulkan/staging_buffer/texture_upload_region_size_px", 64); + GLOBAL_DEF("rendering/vulkan/descriptor_pools/max_descriptors_per_pool", 64); GLOBAL_DEF("rendering/shader_compiler/shader_cache/enabled", true); GLOBAL_DEF("rendering/shader_compiler/shader_cache/compress", true); @@ -2815,7 +2851,7 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/shader_compiler/shader_cache/strip_debug.release", true); GLOBAL_DEF("rendering/reflections/sky_reflections/roughness_layers", 8); - GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections", true); + GLOBAL_DEF_RST("rendering/reflections/sky_reflections/texture_array_reflections", true); GLOBAL_DEF("rendering/reflections/sky_reflections/texture_array_reflections.mobile", false); GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples", 1024); GLOBAL_DEF("rendering/reflections/sky_reflections/ggx_samples.mobile", 128); @@ -2868,6 +2904,29 @@ RenderingServer::RenderingServer() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/amount", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/amount", PROPERTY_HINT_RANGE, "0.01,4.0,0.01")); ProjectSettings::get_singleton()->set_custom_property_info("rendering/anti_aliasing/screen_space_roughness_limiter/limit", PropertyInfo(Variant::FLOAT, "rendering/anti_aliasing/screen_space_roughness_limiter/limit", PROPERTY_HINT_RANGE, "0.01,1.0,0.01")); + GLOBAL_DEF_RST("rendering/scaling_3d/mode", 0); + GLOBAL_DEF_RST("rendering/scaling_3d/scale", 1.0); + GLOBAL_DEF_RST("rendering/scaling_3d/fsr_sharpness", 0.2f); + GLOBAL_DEF_RST("rendering/scaling_3d/fsr_mipmap_bias", 0.0f); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/mode", + PropertyInfo(Variant::INT, + "rendering/scaling_3d/mode", + PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR (Fast)")); + + ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/scale", + PropertyInfo(Variant::FLOAT, + "rendering/scaling_3d/scale", + PROPERTY_HINT_RANGE, "0.25,2.0,0.01")); + + ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/fsr_sharpness", + PropertyInfo(Variant::FLOAT, + "rendering/scaling_3d/fsr_sharpness", + PROPERTY_HINT_RANGE, "0,2,0.1")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/scaling_3d/fsr_mipmap_bias", + PropertyInfo(Variant::FLOAT, + "rendering/scaling_3d/fsr_mipmap_bias", + PROPERTY_HINT_RANGE, "-2,2,0.1")); + GLOBAL_DEF("rendering/textures/decals/filter", DECAL_FILTER_LINEAR_MIPMAPS); ProjectSettings::get_singleton()->set_custom_property_info("rendering/textures/decals/filter", PropertyInfo(Variant::INT, "rendering/textures/decals/filter", PROPERTY_HINT_ENUM, "Nearest (Fast),Nearest+Mipmaps,Linear,Linear+Mipmaps,Linear+Mipmaps Anisotropic (Slow)")); GLOBAL_DEF("rendering/textures/light_projectors/filter", LIGHT_PROJECTOR_FILTER_LINEAR_MIPMAPS); @@ -2906,7 +2965,7 @@ RenderingServer::RenderingServer() { GLOBAL_DEF("rendering/environment/volumetric_fog/volume_size", 64); ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/volume_size", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_size", PROPERTY_HINT_RANGE, "16,512,1")); - GLOBAL_DEF("rendering/environment/volumetric_fog/volume_depth", 128); + GLOBAL_DEF("rendering/environment/volumetric_fog/volume_depth", 64); ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/volume_depth", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1")); GLOBAL_DEF("rendering/environment/volumetric_fog/use_filter", 1); ProjectSettings::get_singleton()->set_custom_property_info("rendering/environment/volumetric_fog/use_filter", PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)")); @@ -2922,6 +2981,43 @@ RenderingServer::RenderingServer() { ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/cluster_builder/max_clustered_elements", PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1")); GLOBAL_DEF_RST("rendering/xr/enabled", false); + + GLOBAL_DEF_RST("rendering/2d/options/use_software_skinning", true); + GLOBAL_DEF_RST("rendering/2d/options/ninepatch_mode", 1); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/options/ninepatch_mode", PropertyInfo(Variant::INT, "rendering/2d/options/ninepatch_mode", PROPERTY_HINT_ENUM, "Fixed,Scaling")); + + GLOBAL_DEF_RST("rendering/2d/opengl/batching_send_null", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/opengl/batching_send_null", PropertyInfo(Variant::INT, "rendering/2d/opengl/batching_send_null", PROPERTY_HINT_ENUM, "Default (On),Off,On")); + GLOBAL_DEF_RST("rendering/2d/opengl/batching_stream", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/opengl/batching_stream", PropertyInfo(Variant::INT, "rendering/2d/opengl/batching_stream", PROPERTY_HINT_ENUM, "Default (Off),Off,On")); + GLOBAL_DEF_RST("rendering/2d/opengl/legacy_orphan_buffers", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/opengl/legacy_orphan_buffers", PropertyInfo(Variant::INT, "rendering/2d/opengl/legacy_orphan_buffers", PROPERTY_HINT_ENUM, "Default (On),Off,On")); + GLOBAL_DEF_RST("rendering/2d/opengl/legacy_stream", 0); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/2d/opengl/legacy_stream", PropertyInfo(Variant::INT, "rendering/2d/opengl/legacy_stream", PROPERTY_HINT_ENUM, "Default (On),Off,On")); + + GLOBAL_DEF("rendering/batching/options/use_batching", false); + GLOBAL_DEF_RST("rendering/batching/options/use_batching_in_editor", false); + GLOBAL_DEF("rendering/batching/options/single_rect_fallback", false); + GLOBAL_DEF("rendering/batching/parameters/max_join_item_commands", 16); + GLOBAL_DEF("rendering/batching/parameters/colored_vertex_format_threshold", 0.25f); + GLOBAL_DEF("rendering/batching/lights/scissor_area_threshold", 1.0f); + GLOBAL_DEF("rendering/batching/lights/max_join_items", 32); + GLOBAL_DEF("rendering/batching/parameters/batch_buffer_size", 16384); + GLOBAL_DEF("rendering/batching/parameters/item_reordering_lookahead", 4); + GLOBAL_DEF("rendering/batching/debug/flash_batching", false); + GLOBAL_DEF("rendering/batching/debug/diagnose_frame", false); + GLOBAL_DEF("rendering/gles2/compatibility/disable_half_float", false); + GLOBAL_DEF("rendering/gles2/compatibility/enable_high_float.Android", false); + GLOBAL_DEF("rendering/batching/precision/uv_contract", false); + GLOBAL_DEF("rendering/batching/precision/uv_contract_amount", 100); + + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/parameters/max_join_item_commands", PropertyInfo(Variant::INT, "rendering/batching/parameters/max_join_item_commands", PROPERTY_HINT_RANGE, "0,65535")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/parameters/colored_vertex_format_threshold", PropertyInfo(Variant::FLOAT, "rendering/batching/parameters/colored_vertex_format_threshold", PROPERTY_HINT_RANGE, "0.0,1.0,0.01")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/parameters/batch_buffer_size", PropertyInfo(Variant::INT, "rendering/batching/parameters/batch_buffer_size", PROPERTY_HINT_RANGE, "1024,65535,1024")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/lights/scissor_area_threshold", PropertyInfo(Variant::FLOAT, "rendering/batching/lights/scissor_area_threshold", PROPERTY_HINT_RANGE, "0.0,1.0")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/lights/max_join_items", PropertyInfo(Variant::INT, "rendering/batching/lights/max_join_items", PROPERTY_HINT_RANGE, "0,512")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/parameters/item_reordering_lookahead", PropertyInfo(Variant::INT, "rendering/batching/parameters/item_reordering_lookahead", PROPERTY_HINT_RANGE, "0,256")); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/batching/precision/uv_contract_amount", PropertyInfo(Variant::INT, "rendering/batching/precision/uv_contract_amount", PROPERTY_HINT_RANGE, "0,10000")); } RenderingServer::~RenderingServer() { diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 8fbf231d9b..85f92bc003 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -161,6 +161,7 @@ public: SHADER_CANVAS_ITEM, SHADER_PARTICLES, SHADER_SKY, + SHADER_FOG, SHADER_MAX }; @@ -171,8 +172,8 @@ public: virtual void shader_get_param_list(RID p_shader, List<PropertyInfo> *p_param_list) const = 0; virtual Variant shader_get_param_default(RID p_shader, const StringName &p_param) const = 0; - virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture) = 0; - virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name) const = 0; + virtual void shader_set_default_texture_param(RID p_shader, const StringName &p_name, RID p_texture, int p_index = 0) = 0; + virtual RID shader_get_default_texture_param(RID p_shader, const StringName &p_name, int p_index = 0) const = 0; struct ShaderNativeSourceCode { struct Version { @@ -295,7 +296,7 @@ public: AABB aabb; struct LOD { - float edge_length; + float edge_length = 0.0f; Vector<uint8_t> index_data; }; Vector<LOD> lods; @@ -474,6 +475,7 @@ public: enum ShadowQuality { SHADOW_QUALITY_HARD, + SHADOW_QUALITY_SOFT_VERY_LOW, SHADOW_QUALITY_SOFT_LOW, SHADOW_QUALITY_SOFT_MEDIUM, SHADOW_QUALITY_SOFT_HIGH, @@ -708,6 +710,20 @@ public: virtual void particles_collision_set_height_field_resolution(RID p_particles_collision, ParticlesCollisionHeightfieldResolution p_resolution) = 0; //for SDF and vector field + /* FOG VOLUME API */ + + virtual RID fog_volume_create() = 0; + + enum FogVolumeShape { + FOG_VOLUME_SHAPE_ELLIPSOID, + FOG_VOLUME_SHAPE_BOX, + FOG_VOLUME_SHAPE_WORLD, + }; + + virtual void fog_volume_set_shape(RID p_fog_volume, FogVolumeShape p_shape) = 0; + virtual void fog_volume_set_extents(RID p_fog_volume, const Vector3 &p_extents) = 0; + virtual void fog_volume_set_material(RID p_fog_volume, RID p_material) = 0; + /* VISIBILITY NOTIFIER API */ virtual RID visibility_notifier_create() = 0; @@ -752,19 +768,15 @@ public: CANVAS_ITEM_TEXTURE_REPEAT_MAX, }; - enum ViewportScale3D { - VIEWPORT_SCALE_3D_DISABLED, - VIEWPORT_SCALE_3D_75_PERCENT, - VIEWPORT_SCALE_3D_50_PERCENT, - VIEWPORT_SCALE_3D_33_PERCENT, - VIEWPORT_SCALE_3D_25_PERCENT, - VIEWPORT_SCALE_3D_MAX, - }; - virtual RID viewport_create() = 0; + enum ViewportScaling3DMode { + VIEWPORT_SCALING_3D_MODE_BILINEAR, + VIEWPORT_SCALING_3D_MODE_FSR, + VIEWPORT_SCALING_3D_MODE_MAX + }; + virtual void viewport_set_use_xr(RID p_viewport, bool p_use_xr) = 0; - virtual void viewport_set_scale_3d(RID p_viewport, ViewportScale3D p_scale_3d) = 0; virtual void viewport_set_size(RID p_viewport, int p_width, int p_height) = 0; virtual void viewport_set_active(RID p_viewport, bool p_active) = 0; virtual void viewport_set_parent_viewport(RID p_viewport, RID p_parent_viewport) = 0; @@ -772,6 +784,11 @@ public: virtual void viewport_attach_to_screen(RID p_viewport, const Rect2 &p_rect = Rect2(), DisplayServer::WindowID p_screen = DisplayServer::MAIN_WINDOW_ID) = 0; virtual void viewport_set_render_direct_to_screen(RID p_viewport, bool p_enable) = 0; + virtual void viewport_set_scaling_3d_mode(RID p_viewport, ViewportScaling3DMode p_scaling_3d_mode) = 0; + virtual void viewport_set_scaling_3d_scale(RID p_viewport, float p_scaling_3d_scale) = 0; + virtual void viewport_set_fsr_sharpness(RID p_viewport, float p_fsr_sharpness) = 0; + virtual void viewport_set_fsr_mipmap_bias(RID p_viewport, float p_fsr_mipmap_bias) = 0; + enum ViewportUpdateMode { VIEWPORT_UPDATE_DISABLED, VIEWPORT_UPDATE_ONCE, //then goes to disabled, must be manually updated @@ -836,7 +853,6 @@ public: VIEWPORT_MSAA_2X, VIEWPORT_MSAA_4X, VIEWPORT_MSAA_8X, - VIEWPORT_MSAA_16X, VIEWPORT_MSAA_MAX, }; @@ -962,7 +978,7 @@ public: virtual void environment_set_bg_color(RID p_env, const Color &p_color) = 0; virtual void environment_set_bg_energy(RID p_env, float p_energy) = 0; virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer) = 0; - virtual void environment_set_ambient_light(RID p_env, const Color &p_color, EnvironmentAmbientSource p_ambient = ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, EnvironmentReflectionSource p_reflection_source = ENV_REFLECTION_SOURCE_BG, const Color &p_ao_color = Color()) = 0; + virtual void environment_set_ambient_light(RID p_env, const Color &p_color, EnvironmentAmbientSource p_ambient = ENV_AMBIENT_SOURCE_BG, float p_energy = 1.0, float p_sky_contribution = 0.0, EnvironmentReflectionSource p_reflection_source = ENV_REFLECTION_SOURCE_BG) = 0; enum EnvironmentGlowBlendMode { ENV_GLOW_BLEND_MODE_ADDITIVE, @@ -1062,7 +1078,7 @@ public: virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_light_color, float p_light_energy, float p_sun_scatter, float p_density, float p_height, float p_height_density, float p_aerial_perspective) = 0; - virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_light, float p_light_energy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount) = 0; + virtual void environment_set_volumetric_fog(RID p_env, bool p_enable, float p_density, const Color &p_albedo, const Color &p_emission, float p_emission_energy, float p_anisotropy, float p_length, float p_detail_spread, float p_gi_inject, bool p_temporal_reprojection, float p_temporal_reprojection_amount, float p_ambient_inject) = 0; virtual void environment_set_volumetric_fog_volume_size(int p_size, int p_depth) = 0; virtual void environment_set_volumetric_fog_filter_active(bool p_enable) = 0; @@ -1127,6 +1143,7 @@ public: INSTANCE_LIGHTMAP, INSTANCE_OCCLUDER, INSTANCE_VISIBLITY_NOTIFIER, + INSTANCE_FOG_VOLUME, INSTANCE_MAX, INSTANCE_GEOMETRY_MASK = (1 << INSTANCE_MESH) | (1 << INSTANCE_MULTIMESH) | (1 << INSTANCE_PARTICLES) @@ -1152,6 +1169,8 @@ public: virtual void instance_set_extra_visibility_margin(RID p_instance, real_t p_margin) = 0; virtual void instance_set_visibility_parent(RID p_instance, RID p_parent_instance) = 0; + virtual void instance_set_ignore_culling(RID p_instance, bool p_enabled) = 0; + // don't use these in a game! virtual Vector<ObjectID> instances_cull_aabb(const AABB &p_aabb, RID p_scenario = RID()) const = 0; virtual Vector<ObjectID> instances_cull_ray(const Vector3 &p_from, const Vector3 &p_to, RID p_scenario = RID()) const = 0; @@ -1176,12 +1195,19 @@ public: SHADOW_CASTING_SETTING_SHADOWS_ONLY, }; + enum VisibilityRangeFadeMode { + VISIBILITY_RANGE_FADE_DISABLED, + VISIBILITY_RANGE_FADE_SELF, + VISIBILITY_RANGE_FADE_DEPENDENCIES, + }; + virtual void instance_geometry_set_flag(RID p_instance, InstanceFlags p_flags, bool p_enabled) = 0; virtual void instance_geometry_set_cast_shadows_setting(RID p_instance, ShadowCastingSetting p_shadow_casting_setting) = 0; virtual void instance_geometry_set_material_override(RID p_instance, RID p_material) = 0; - virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin) = 0; + virtual void instance_geometry_set_visibility_range(RID p_instance, float p_min, float p_max, float p_min_margin, float p_max_margin, VisibilityRangeFadeMode p_fade_mode) = 0; virtual void instance_geometry_set_lightmap(RID p_instance, RID p_lightmap, const Rect2 &p_lightmap_uv_scale, int p_lightmap_slice) = 0; virtual void instance_geometry_set_lod_bias(RID p_instance, float p_lod_bias) = 0; + virtual void instance_geometry_set_transparency(RID p_instance, float p_transparency) = 0; virtual void instance_geometry_set_shader_parameter(RID p_instance, const StringName &, const Variant &p_value) = 0; virtual Variant instance_geometry_get_shader_parameter(RID p_instance, const StringName &) const = 0; @@ -1417,12 +1443,12 @@ public: /* FREE */ - virtual void free(RID p_rid) = 0; ///< free RIDs associated with the visual server - - virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata) = 0; + virtual void free(RID p_rid) = 0; ///< free RIDs associated with the rendering server /* EVENT QUEUING */ + virtual void request_frame_drawn_callback(const Callable &p_callable) = 0; + virtual void draw(bool p_swap_buffers = true, double frame_step = 0.0) = 0; virtual void sync() = 0; virtual bool has_changed() const = 0; @@ -1493,6 +1519,7 @@ public: virtual void set_print_gpu_profile(bool p_enable) = 0; + RenderingDevice *get_rendering_device() const; RenderingDevice *create_local_rendering_device() const; bool is_render_loop_enabled() const; @@ -1543,6 +1570,8 @@ VARIANT_ENUM_CAST(RenderingServer::ParticlesDrawOrder); VARIANT_ENUM_CAST(RenderingServer::ParticlesEmitFlags); VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionType); VARIANT_ENUM_CAST(RenderingServer::ParticlesCollisionHeightfieldResolution); +VARIANT_ENUM_CAST(RenderingServer::FogVolumeShape); +VARIANT_ENUM_CAST(RenderingServer::ViewportScaling3DMode); VARIANT_ENUM_CAST(RenderingServer::ViewportUpdateMode); VARIANT_ENUM_CAST(RenderingServer::ViewportClearMode); VARIANT_ENUM_CAST(RenderingServer::ViewportMSAA); @@ -1553,7 +1582,6 @@ VARIANT_ENUM_CAST(RenderingServer::ViewportDebugDraw); VARIANT_ENUM_CAST(RenderingServer::ViewportOcclusionCullingBuildQuality); VARIANT_ENUM_CAST(RenderingServer::ViewportSDFOversize); VARIANT_ENUM_CAST(RenderingServer::ViewportSDFScale); -VARIANT_ENUM_CAST(RenderingServer::ViewportScale3D); VARIANT_ENUM_CAST(RenderingServer::SkyMode); VARIANT_ENUM_CAST(RenderingServer::EnvironmentBG); VARIANT_ENUM_CAST(RenderingServer::EnvironmentAmbientSource); @@ -1574,6 +1602,7 @@ VARIANT_ENUM_CAST(RenderingServer::ShadowQuality); VARIANT_ENUM_CAST(RenderingServer::InstanceType); VARIANT_ENUM_CAST(RenderingServer::InstanceFlags); VARIANT_ENUM_CAST(RenderingServer::ShadowCastingSetting); +VARIANT_ENUM_CAST(RenderingServer::VisibilityRangeFadeMode); VARIANT_ENUM_CAST(RenderingServer::NinePatchAxisMode); VARIANT_ENUM_CAST(RenderingServer::CanvasItemTextureFilter); VARIANT_ENUM_CAST(RenderingServer::CanvasItemTextureRepeat); diff --git a/servers/text/SCsub b/servers/text/SCsub new file mode 100644 index 0000000000..86681f9c74 --- /dev/null +++ b/servers/text/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp new file mode 100644 index 0000000000..d6d98b4f8f --- /dev/null +++ b/servers/text/text_server_extension.cpp @@ -0,0 +1,1350 @@ +/*************************************************************************/ +/* text_server_extension.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "text_server_extension.h" + +void TextServerExtension::_bind_methods() { + GDVIRTUAL_BIND(_has_feature, "feature"); + GDVIRTUAL_BIND(_get_name); + GDVIRTUAL_BIND(_get_features); + + GDVIRTUAL_BIND(_free, "rid"); + GDVIRTUAL_BIND(_has, "rid"); + GDVIRTUAL_BIND(_load_support_data, "filename"); + + GDVIRTUAL_BIND(_get_support_data_filename); + GDVIRTUAL_BIND(_get_support_data_info); + GDVIRTUAL_BIND(_save_support_data, "filename"); + + GDVIRTUAL_BIND(_is_locale_right_to_left, "locale"); + + GDVIRTUAL_BIND(_name_to_tag, "name"); + GDVIRTUAL_BIND(_tag_to_name, "tag"); + + /* Font interface */ + + GDVIRTUAL_BIND(_create_font); + + GDVIRTUAL_BIND(_font_set_data, "font_rid", "data"); + GDVIRTUAL_BIND(_font_set_data_ptr, "font_rid", "data_ptr", "data_size"); + + GDVIRTUAL_BIND(_font_set_style, "font_rid", "style"); + GDVIRTUAL_BIND(_font_get_style, "font_rid"); + + GDVIRTUAL_BIND(_font_set_name, "font_rid", "name"); + GDVIRTUAL_BIND(_font_get_name, "font_rid"); + + GDVIRTUAL_BIND(_font_set_style_name, "font_rid", "name_style"); + GDVIRTUAL_BIND(_font_get_style_name, "font_rid"); + + GDVIRTUAL_BIND(_font_set_antialiased, "font_rid", "antialiased"); + GDVIRTUAL_BIND(_font_is_antialiased, "font_rid"); + + GDVIRTUAL_BIND(_font_set_multichannel_signed_distance_field, "font_rid", "msdf"); + GDVIRTUAL_BIND(_font_is_multichannel_signed_distance_field, "font_rid"); + + GDVIRTUAL_BIND(_font_set_msdf_pixel_range, "font_rid", "msdf_pixel_range"); + GDVIRTUAL_BIND(_font_get_msdf_pixel_range, "font_rid"); + + GDVIRTUAL_BIND(_font_set_msdf_size, "font_rid", "msdf_size"); + GDVIRTUAL_BIND(_font_get_msdf_size, "font_rid"); + + GDVIRTUAL_BIND(_font_set_fixed_size, "font_rid", "fixed_size"); + GDVIRTUAL_BIND(_font_get_fixed_size, "font_rid"); + + GDVIRTUAL_BIND(_font_set_force_autohinter, "font_rid", "force_autohinter"); + GDVIRTUAL_BIND(_font_is_force_autohinter, "font_rid"); + + GDVIRTUAL_BIND(_font_set_hinting, "font_rid", "hinting"); + GDVIRTUAL_BIND(_font_get_hinting, "font_rid"); + + GDVIRTUAL_BIND(_font_set_variation_coordinates, "font_rid", "variation_coordinates"); + GDVIRTUAL_BIND(_font_get_variation_coordinates, "font_rid"); + + GDVIRTUAL_BIND(_font_set_oversampling, "font_rid", "oversampling"); + GDVIRTUAL_BIND(_font_get_oversampling, "font_rid"); + + GDVIRTUAL_BIND(_font_get_size_cache_list, "font_rid"); + GDVIRTUAL_BIND(_font_clear_size_cache, "font_rid"); + GDVIRTUAL_BIND(_font_remove_size_cache, "font_rid", "size"); + + GDVIRTUAL_BIND(_font_set_ascent, "font_rid", "size", "ascent"); + GDVIRTUAL_BIND(_font_get_ascent, "font_rid", "size"); + + GDVIRTUAL_BIND(_font_set_descent, "font_rid", "size", "descent"); + GDVIRTUAL_BIND(_font_get_descent, "font_rid", "size"); + + GDVIRTUAL_BIND(_font_set_underline_position, "font_rid", "size", "underline_position"); + GDVIRTUAL_BIND(_font_get_underline_position, "font_rid", "size"); + + GDVIRTUAL_BIND(_font_set_underline_thickness, "font_rid", "size", "underline_thickness"); + GDVIRTUAL_BIND(_font_get_underline_thickness, "font_rid", "size"); + + GDVIRTUAL_BIND(_font_set_scale, "font_rid", "size", "scale"); + GDVIRTUAL_BIND(_font_get_scale, "font_rid", "size"); + + GDVIRTUAL_BIND(_font_set_spacing, "font_rid", "size", "spacing", "value"); + GDVIRTUAL_BIND(_font_get_spacing, "font_rid", "size", "spacing"); + + GDVIRTUAL_BIND(_font_get_texture_count, "font_rid", "size"); + GDVIRTUAL_BIND(_font_clear_textures, "font_rid", "size"); + GDVIRTUAL_BIND(_font_remove_texture, "font_rid", "size", "texture_index"); + + GDVIRTUAL_BIND(_font_set_texture_image, "font_rid", "size", "texture_index", "image"); + GDVIRTUAL_BIND(_font_get_texture_image, "font_rid", "size", "texture_index"); + + GDVIRTUAL_BIND(_font_set_texture_offsets, "font_rid", "size", "texture_index", "offset"); + GDVIRTUAL_BIND(_font_get_texture_offsets, "font_rid", "size", "texture_index"); + + GDVIRTUAL_BIND(_font_get_glyph_list, "font_rid", "size"); + GDVIRTUAL_BIND(_font_clear_glyphs, "font_rid", "size"); + GDVIRTUAL_BIND(_font_remove_glyph, "font_rid", "size", "glyph"); + + GDVIRTUAL_BIND(_font_get_glyph_advance, "font_rid", "size", "glyph"); + GDVIRTUAL_BIND(_font_set_glyph_advance, "font_rid", "size", "glyph", "advance"); + + GDVIRTUAL_BIND(_font_get_glyph_offset, "font_rid", "size", "glyph"); + GDVIRTUAL_BIND(_font_set_glyph_offset, "font_rid", "size", "glyph", "offset"); + + GDVIRTUAL_BIND(_font_get_glyph_size, "font_rid", "size", "glyph"); + GDVIRTUAL_BIND(_font_set_glyph_size, "font_rid", "size", "glyph", "gl_size"); + + GDVIRTUAL_BIND(_font_get_glyph_uv_rect, "font_rid", "size", "glyph"); + GDVIRTUAL_BIND(_font_set_glyph_uv_rect, "font_rid", "size", "glyph", "uv_rect"); + + GDVIRTUAL_BIND(_font_get_glyph_texture_idx, "font_rid", "size", "glyph"); + GDVIRTUAL_BIND(_font_set_glyph_texture_idx, "font_rid", "size", "glyph", "texture_idx"); + + GDVIRTUAL_BIND(_font_get_glyph_contours, "font_rid", "size", "index"); + + GDVIRTUAL_BIND(_font_get_kerning_list, "font_rid", "size"); + GDVIRTUAL_BIND(_font_clear_kerning_map, "font_rid", "size"); + GDVIRTUAL_BIND(_font_remove_kerning, "font_rid", "size", "glyph_pair"); + + GDVIRTUAL_BIND(_font_set_kerning, "font_rid", "size", "glyph_pair", "kerning"); + GDVIRTUAL_BIND(_font_get_kerning, "font_rid", "size", "glyph_pair"); + + GDVIRTUAL_BIND(_font_get_glyph_index, "font_rid", "size", "char", "variation_selector"); + + GDVIRTUAL_BIND(_font_has_char, "font_rid", "char"); + GDVIRTUAL_BIND(_font_get_supported_chars, "font_rid"); + + GDVIRTUAL_BIND(_font_render_range, "font_rid", "size", "start", "end"); + GDVIRTUAL_BIND(_font_render_glyph, "font_rid", "size", "index"); + + GDVIRTUAL_BIND(_font_draw_glyph, "font_rid", "canvas", "size", "pos", "index", "color"); + GDVIRTUAL_BIND(_font_draw_glyph_outline, "font_rid", "canvas", "size", "outline_size", "pos", "index", "color"); + + GDVIRTUAL_BIND(_font_is_language_supported, "font_rid", "language"); + GDVIRTUAL_BIND(_font_set_language_support_override, "font_rid", "language", "supported"); + GDVIRTUAL_BIND(_font_get_language_support_override, "font_rid", "language"); + GDVIRTUAL_BIND(_font_remove_language_support_override, "font_rid", "language"); + GDVIRTUAL_BIND(_font_get_language_support_overrides, "font_rid"); + + GDVIRTUAL_BIND(_font_is_script_supported, "font_rid", "script"); + GDVIRTUAL_BIND(_font_set_script_support_override, "font_rid", "script", "supported"); + GDVIRTUAL_BIND(_font_get_script_support_override, "font_rid", "script"); + GDVIRTUAL_BIND(_font_remove_script_support_override, "font_rid", "script"); + GDVIRTUAL_BIND(_font_get_script_support_overrides, "font_rid"); + + GDVIRTUAL_BIND(_font_supported_feature_list, "font_rid"); + GDVIRTUAL_BIND(_font_supported_variation_list, "font_rid"); + + GDVIRTUAL_BIND(_font_get_global_oversampling); + GDVIRTUAL_BIND(_font_set_global_oversampling, "oversampling"); + + GDVIRTUAL_BIND(_get_hex_code_box_size, "size", "index"); + GDVIRTUAL_BIND(_draw_hex_code_box, "canvas", "size", "pos", "index", "color"); + + /* Shaped text buffer interface */ + + GDVIRTUAL_BIND(_create_shaped_text, "direction", "orientation"); + + GDVIRTUAL_BIND(_shaped_text_clear, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_set_direction, "shaped", "direction"); + GDVIRTUAL_BIND(_shaped_text_get_direction, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_set_bidi_override, "shaped", "override"); + + GDVIRTUAL_BIND(_shaped_text_set_custom_punctuation, "shaped", "punct"); + GDVIRTUAL_BIND(_shaped_text_get_custom_punctuation, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_set_orientation, "shaped", "orientation"); + GDVIRTUAL_BIND(_shaped_text_get_orientation, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_set_preserve_invalid, "shaped", "enabled"); + GDVIRTUAL_BIND(_shaped_text_get_preserve_invalid, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_set_preserve_control, "shaped", "enabled"); + GDVIRTUAL_BIND(_shaped_text_get_preserve_control, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_add_string, "shaped", "text", "fonts", "size", "opentype_features", "language"); + GDVIRTUAL_BIND(_shaped_text_add_object, "shaped", "key", "size", "inline_align", "length"); + GDVIRTUAL_BIND(_shaped_text_resize_object, "shaped", "key", "size", "inline_align"); + + GDVIRTUAL_BIND(_shaped_text_substr, "shaped", "start", "length"); + GDVIRTUAL_BIND(_shaped_text_get_parent, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_fit_to_width, "shaped", "width", "jst_flags"); + GDVIRTUAL_BIND(_shaped_text_tab_align, "shaped", "tab_stops"); + + GDVIRTUAL_BIND(_shaped_text_shape, "shaped"); + GDVIRTUAL_BIND(_shaped_text_update_breaks, "shaped"); + GDVIRTUAL_BIND(_shaped_text_update_justification_ops, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_is_ready, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_get_glyphs, "shaped", "r_glyphs"); + GDVIRTUAL_BIND(_shaped_text_sort_logical, "shaped", "r_glyphs"); + GDVIRTUAL_BIND(_shaped_text_get_glyph_count, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_get_range, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_get_line_breaks_adv, "shaped", "width", "start", "once", "break_flags"); + GDVIRTUAL_BIND(_shaped_text_get_line_breaks, "shaped", "width", "start", "break_flags"); + GDVIRTUAL_BIND(_shaped_text_get_word_breaks, "shaped", "grapheme_flags"); + + GDVIRTUAL_BIND(_shaped_text_get_trim_pos, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_ellipsis_pos, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyph_count, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_ellipsis_glyphs, "shaped", "r_glyphs"); + + GDVIRTUAL_BIND(_shaped_text_overrun_trim_to_width, "shaped", "width", "trim_flags"); + + GDVIRTUAL_BIND(_shaped_text_get_objects, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_object_rect, "shaped", "key"); + + GDVIRTUAL_BIND(_shaped_text_get_size, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_ascent, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_descent, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_width, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_underline_position, "shaped"); + GDVIRTUAL_BIND(_shaped_text_get_underline_thickness, "shaped"); + + GDVIRTUAL_BIND(_shaped_text_get_dominant_direction_in_range, "shaped", "start", "end"); + + GDVIRTUAL_BIND(_shaped_text_get_carets, "shaped", "position", "caret"); + GDVIRTUAL_BIND(_shaped_text_get_selection, "shaped", "start", "end"); + + GDVIRTUAL_BIND(_shaped_text_hit_test_grapheme, "shaped", "coord"); + GDVIRTUAL_BIND(_shaped_text_hit_test_position, "shaped", "coord"); + + GDVIRTUAL_BIND(_shaped_text_draw, "shaped", "canvas", "pos", "clip_l", "clip_r", "color"); + GDVIRTUAL_BIND(_shaped_text_draw_outline, "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color"); + + GDVIRTUAL_BIND(_shaped_text_get_grapheme_bounds, "shaped", "pos"); + GDVIRTUAL_BIND(_shaped_text_next_grapheme_pos, "shaped", "pos"); + GDVIRTUAL_BIND(_shaped_text_prev_grapheme_pos, "shaped", "pos"); + + GDVIRTUAL_BIND(_format_number, "string", "language"); + GDVIRTUAL_BIND(_parse_number, "string", "language"); + GDVIRTUAL_BIND(_percent_sign, "language"); +} + +bool TextServerExtension::has_feature(Feature p_feature) const { + bool ret; + if (GDVIRTUAL_CALL(_has_feature, p_feature, ret)) { + return ret; + } + return false; +} + +String TextServerExtension::get_name() const { + String ret; + if (GDVIRTUAL_CALL(_get_name, ret)) { + return ret; + } + return "Unknown"; +} + +uint32_t TextServerExtension::get_features() const { + uint32_t ret; + if (GDVIRTUAL_CALL(_get_features, ret)) { + return ret; + } + return 0; +} + +void TextServerExtension::free(RID p_rid) { + GDVIRTUAL_CALL(_free, p_rid); +} + +bool TextServerExtension::has(RID p_rid) { + bool ret; + if (GDVIRTUAL_CALL(_has, p_rid, ret)) { + return ret; + } + return false; +} + +bool TextServerExtension::load_support_data(const String &p_filename) { + bool ret; + if (GDVIRTUAL_CALL(_load_support_data, p_filename, ret)) { + return ret; + } + return false; +} + +String TextServerExtension::get_support_data_filename() const { + String ret; + if (GDVIRTUAL_CALL(_get_support_data_filename, ret)) { + return ret; + } + return String(); +} + +String TextServerExtension::get_support_data_info() const { + String ret; + if (GDVIRTUAL_CALL(_get_support_data_info, ret)) { + return ret; + } + return String(); +} + +bool TextServerExtension::save_support_data(const String &p_filename) const { + bool ret; + if (GDVIRTUAL_CALL(_save_support_data, p_filename, ret)) { + return ret; + } + return false; +} + +bool TextServerExtension::is_locale_right_to_left(const String &p_locale) const { + bool ret; + if (GDVIRTUAL_CALL(_is_locale_right_to_left, p_locale, ret)) { + return ret; + } + return false; +} + +int32_t TextServerExtension::name_to_tag(const String &p_name) const { + int32_t ret; + if (GDVIRTUAL_CALL(_name_to_tag, p_name, ret)) { + return ret; + } + return 0; +} + +String TextServerExtension::tag_to_name(int32_t p_tag) const { + String ret; + if (GDVIRTUAL_CALL(_tag_to_name, p_tag, ret)) { + return ret; + } + return ""; +} + +/*************************************************************************/ +/* Font */ +/*************************************************************************/ + +RID TextServerExtension::create_font() { + RID ret; + if (GDVIRTUAL_CALL(_create_font, ret)) { + return ret; + } + return RID(); +} + +void TextServerExtension::font_set_data(RID p_font_rid, const PackedByteArray &p_data) { + GDVIRTUAL_CALL(_font_set_data, p_font_rid, p_data); +} + +void TextServerExtension::font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) { + GDVIRTUAL_CALL(_font_set_data_ptr, p_font_rid, p_data_ptr, p_data_size); +} + +void TextServerExtension::font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) { + GDVIRTUAL_CALL(_font_set_style, p_font_rid, p_style); +} + +uint32_t /*FontStyle*/ TextServerExtension::font_get_style(RID p_font_rid) const { + uint32_t ret; + if (GDVIRTUAL_CALL(_font_get_style, p_font_rid, ret)) { + return ret; + } + return 0; +} + +void TextServerExtension::font_set_style_name(RID p_font_rid, const String &p_name) { + GDVIRTUAL_CALL(_font_set_style_name, p_font_rid, p_name); +} + +String TextServerExtension::font_get_style_name(RID p_font_rid) const { + String ret; + if (GDVIRTUAL_CALL(_font_get_style_name, p_font_rid, ret)) { + return ret; + } + return String(); +} + +void TextServerExtension::font_set_name(RID p_font_rid, const String &p_name) { + GDVIRTUAL_CALL(_font_set_name, p_font_rid, p_name); +} + +String TextServerExtension::font_get_name(RID p_font_rid) const { + String ret; + if (GDVIRTUAL_CALL(_font_get_name, p_font_rid, ret)) { + return ret; + } + return String(); +} + +void TextServerExtension::font_set_antialiased(RID p_font_rid, bool p_antialiased) { + GDVIRTUAL_CALL(_font_set_antialiased, p_font_rid, p_antialiased); +} + +bool TextServerExtension::font_is_antialiased(RID p_font_rid) const { + bool ret; + if (GDVIRTUAL_CALL(_font_is_antialiased, p_font_rid, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) { + GDVIRTUAL_CALL(_font_set_multichannel_signed_distance_field, p_font_rid, p_msdf); +} + +bool TextServerExtension::font_is_multichannel_signed_distance_field(RID p_font_rid) const { + bool ret; + if (GDVIRTUAL_CALL(_font_is_multichannel_signed_distance_field, p_font_rid, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) { + GDVIRTUAL_CALL(_font_set_msdf_pixel_range, p_font_rid, p_msdf_pixel_range); +} + +int TextServerExtension::font_get_msdf_pixel_range(RID p_font_rid) const { + int ret; + if (GDVIRTUAL_CALL(_font_get_msdf_pixel_range, p_font_rid, ret)) { + return ret; + } + return 0; +} + +void TextServerExtension::font_set_msdf_size(RID p_font_rid, int p_msdf_size) { + GDVIRTUAL_CALL(_font_set_msdf_size, p_font_rid, p_msdf_size); +} + +int TextServerExtension::font_get_msdf_size(RID p_font_rid) const { + int ret; + if (GDVIRTUAL_CALL(_font_get_msdf_size, p_font_rid, ret)) { + return ret; + } + return 0; +} + +void TextServerExtension::font_set_fixed_size(RID p_font_rid, int p_fixed_size) { + GDVIRTUAL_CALL(_font_set_fixed_size, p_font_rid, p_fixed_size); +} + +int TextServerExtension::font_get_fixed_size(RID p_font_rid) const { + int ret; + if (GDVIRTUAL_CALL(_font_get_fixed_size, p_font_rid, ret)) { + return ret; + } + return 0; +} + +void TextServerExtension::font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) { + GDVIRTUAL_CALL(_font_set_force_autohinter, p_font_rid, p_force_autohinter); +} + +bool TextServerExtension::font_is_force_autohinter(RID p_font_rid) const { + bool ret; + if (GDVIRTUAL_CALL(_font_is_force_autohinter, p_font_rid, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) { + GDVIRTUAL_CALL(_font_set_hinting, p_font_rid, p_hinting); +} + +TextServer::Hinting TextServerExtension::font_get_hinting(RID p_font_rid) const { + int ret; + if (GDVIRTUAL_CALL(_font_get_hinting, p_font_rid, ret)) { + return (TextServer::Hinting)ret; + } + return TextServer::Hinting::HINTING_NONE; +} + +void TextServerExtension::font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) { + GDVIRTUAL_CALL(_font_set_variation_coordinates, p_font_rid, p_variation_coordinates); +} + +Dictionary TextServerExtension::font_get_variation_coordinates(RID p_font_rid) const { + Dictionary ret; + if (GDVIRTUAL_CALL(_font_get_variation_coordinates, p_font_rid, ret)) { + return ret; + } + return Dictionary(); +} + +void TextServerExtension::font_set_oversampling(RID p_font_rid, float p_oversampling) { + GDVIRTUAL_CALL(_font_set_oversampling, p_font_rid, p_oversampling); +} + +float TextServerExtension::font_get_oversampling(RID p_font_rid) const { + float ret; + if (GDVIRTUAL_CALL(_font_get_oversampling, p_font_rid, ret)) { + return ret; + } + return 0.f; +} + +Array TextServerExtension::font_get_size_cache_list(RID p_font_rid) const { + Array ret; + if (GDVIRTUAL_CALL(_font_get_size_cache_list, p_font_rid, ret)) { + return ret; + } + return Array(); +} + +void TextServerExtension::font_clear_size_cache(RID p_font_rid) { + GDVIRTUAL_CALL(_font_clear_size_cache, p_font_rid); +} + +void TextServerExtension::font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) { + GDVIRTUAL_CALL(_font_remove_size_cache, p_font_rid, p_size); +} + +void TextServerExtension::font_set_ascent(RID p_font_rid, int p_size, float p_ascent) { + GDVIRTUAL_CALL(_font_set_ascent, p_font_rid, p_size, p_ascent); +} + +float TextServerExtension::font_get_ascent(RID p_font_rid, int p_size) const { + float ret; + if (GDVIRTUAL_CALL(_font_get_ascent, p_font_rid, p_size, ret)) { + return ret; + } + return 0.f; +} + +void TextServerExtension::font_set_descent(RID p_font_rid, int p_size, float p_descent) { + GDVIRTUAL_CALL(_font_set_descent, p_font_rid, p_size, p_descent); +} + +float TextServerExtension::font_get_descent(RID p_font_rid, int p_size) const { + float ret; + if (GDVIRTUAL_CALL(_font_get_descent, p_font_rid, p_size, ret)) { + return ret; + } + return 0.f; +} + +void TextServerExtension::font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) { + GDVIRTUAL_CALL(_font_set_underline_position, p_font_rid, p_size, p_underline_position); +} + +float TextServerExtension::font_get_underline_position(RID p_font_rid, int p_size) const { + float ret; + if (GDVIRTUAL_CALL(_font_get_underline_position, p_font_rid, p_size, ret)) { + return ret; + } + return 0.f; +} + +void TextServerExtension::font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) { + GDVIRTUAL_CALL(_font_set_underline_thickness, p_font_rid, p_size, p_underline_thickness); +} + +float TextServerExtension::font_get_underline_thickness(RID p_font_rid, int p_size) const { + float ret; + if (GDVIRTUAL_CALL(_font_get_underline_thickness, p_font_rid, p_size, ret)) { + return ret; + } + return 0.f; +} + +void TextServerExtension::font_set_scale(RID p_font_rid, int p_size, float p_scale) { + GDVIRTUAL_CALL(_font_set_scale, p_font_rid, p_size, p_scale); +} + +float TextServerExtension::font_get_scale(RID p_font_rid, int p_size) const { + float ret; + if (GDVIRTUAL_CALL(_font_get_scale, p_font_rid, p_size, ret)) { + return ret; + } + return 0.f; +} + +void TextServerExtension::font_set_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing, int p_value) { + GDVIRTUAL_CALL(_font_set_spacing, p_font_rid, p_size, p_spacing, p_value); +} + +int TextServerExtension::font_get_spacing(RID p_font_rid, int p_size, TextServer::SpacingType p_spacing) const { + int ret; + if (GDVIRTUAL_CALL(_font_get_spacing, p_font_rid, p_size, p_spacing, ret)) { + return ret; + } + return 0; +} + +int TextServerExtension::font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const { + int ret; + if (GDVIRTUAL_CALL(_font_get_texture_count, p_font_rid, p_size, ret)) { + return ret; + } + return 0; +} + +void TextServerExtension::font_clear_textures(RID p_font_rid, const Vector2i &p_size) { + GDVIRTUAL_CALL(_font_clear_textures, p_font_rid, p_size); +} + +void TextServerExtension::font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) { + GDVIRTUAL_CALL(_font_remove_texture, p_font_rid, p_size, p_texture_index); +} + +void TextServerExtension::font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) { + GDVIRTUAL_CALL(_font_set_texture_image, p_font_rid, p_size, p_texture_index, p_image); +} + +Ref<Image> TextServerExtension::font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const { + Ref<Image> ret; + if (GDVIRTUAL_CALL(_font_get_texture_image, p_font_rid, p_size, p_texture_index, ret)) { + return ret; + } + return Ref<Image>(); +} + +void TextServerExtension::font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) { + GDVIRTUAL_CALL(_font_set_texture_offsets, p_font_rid, p_size, p_texture_index, p_offset); +} + +PackedInt32Array TextServerExtension::font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const { + PackedInt32Array ret; + if (GDVIRTUAL_CALL(_font_get_texture_offsets, p_font_rid, p_size, p_texture_index, ret)) { + return ret; + } + return PackedInt32Array(); +} + +Array TextServerExtension::font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const { + Array ret; + if (GDVIRTUAL_CALL(_font_get_glyph_list, p_font_rid, p_size, ret)) { + return ret; + } + return Array(); +} + +void TextServerExtension::font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) { + GDVIRTUAL_CALL(_font_clear_glyphs, p_font_rid, p_size); +} + +void TextServerExtension::font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) { + GDVIRTUAL_CALL(_font_remove_glyph, p_font_rid, p_size, p_glyph); +} + +Vector2 TextServerExtension::font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const { + Vector2 ret; + if (GDVIRTUAL_CALL(_font_get_glyph_advance, p_font_rid, p_size, p_glyph, ret)) { + return ret; + } + return Vector2(); +} + +void TextServerExtension::font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) { + GDVIRTUAL_CALL(_font_set_glyph_advance, p_font_rid, p_size, p_glyph, p_advance); +} + +Vector2 TextServerExtension::font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { + Vector2 ret; + if (GDVIRTUAL_CALL(_font_get_glyph_offset, p_font_rid, p_size, p_glyph, ret)) { + return ret; + } + return Vector2(); +} + +void TextServerExtension::font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) { + GDVIRTUAL_CALL(_font_set_glyph_offset, p_font_rid, p_size, p_glyph, p_offset); +} + +Vector2 TextServerExtension::font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { + Vector2 ret; + if (GDVIRTUAL_CALL(_font_get_glyph_size, p_font_rid, p_size, p_glyph, ret)) { + return ret; + } + return Vector2(); +} + +void TextServerExtension::font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) { + GDVIRTUAL_CALL(_font_set_glyph_size, p_font_rid, p_size, p_glyph, p_gl_size); +} + +Rect2 TextServerExtension::font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { + Rect2 ret; + if (GDVIRTUAL_CALL(_font_get_glyph_uv_rect, p_font_rid, p_size, p_glyph, ret)) { + return ret; + } + return Rect2(); +} + +void TextServerExtension::font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) { + GDVIRTUAL_CALL(_font_set_glyph_uv_rect, p_font_rid, p_size, p_glyph, p_uv_rect); +} + +int TextServerExtension::font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const { + int ret; + if (GDVIRTUAL_CALL(_font_get_glyph_texture_idx, p_font_rid, p_size, p_glyph, ret)) { + return ret; + } + return 0; +} + +void TextServerExtension::font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) { + GDVIRTUAL_CALL(_font_set_glyph_texture_idx, p_font_rid, p_size, p_glyph, p_texture_idx); +} + +Dictionary TextServerExtension::font_get_glyph_contours(RID p_font_rid, int p_size, int32_t p_index) const { + Dictionary ret; + if (GDVIRTUAL_CALL(_font_get_glyph_contours, p_font_rid, p_size, p_index, ret)) { + return ret; + } + return Dictionary(); +} + +Array TextServerExtension::font_get_kerning_list(RID p_font_rid, int p_size) const { + Array ret; + if (GDVIRTUAL_CALL(_font_get_kerning_list, p_font_rid, p_size, ret)) { + return ret; + } + return Array(); +} + +void TextServerExtension::font_clear_kerning_map(RID p_font_rid, int p_size) { + GDVIRTUAL_CALL(_font_clear_kerning_map, p_font_rid, p_size); +} + +void TextServerExtension::font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) { + GDVIRTUAL_CALL(_font_remove_kerning, p_font_rid, p_size, p_glyph_pair); +} + +void TextServerExtension::font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) { + GDVIRTUAL_CALL(_font_set_kerning, p_font_rid, p_size, p_glyph_pair, p_kerning); +} + +Vector2 TextServerExtension::font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const { + Vector2 ret; + if (GDVIRTUAL_CALL(_font_get_kerning, p_font_rid, p_size, p_glyph_pair, ret)) { + return ret; + } + return Vector2(); +} + +int32_t TextServerExtension::font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector) const { + int32_t ret; + if (GDVIRTUAL_CALL(_font_get_glyph_index, p_font_rid, p_size, p_char, p_variation_selector, ret)) { + return ret; + } + return 0; +} + +bool TextServerExtension::font_has_char(RID p_font_rid, char32_t p_char) const { + bool ret; + if (GDVIRTUAL_CALL(_font_has_char, p_font_rid, p_char, ret)) { + return ret; + } + return false; +} + +String TextServerExtension::font_get_supported_chars(RID p_font_rid) const { + String ret; + if (GDVIRTUAL_CALL(_font_get_supported_chars, p_font_rid, ret)) { + return ret; + } + return String(); +} + +void TextServerExtension::font_render_range(RID p_font_rid, const Vector2i &p_size, char32_t p_start, char32_t p_end) { + GDVIRTUAL_CALL(_font_render_range, p_font_rid, p_size, p_start, p_end); +} + +void TextServerExtension::font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) { + GDVIRTUAL_CALL(_font_render_glyph, p_font_rid, p_size, p_index); +} + +void TextServerExtension::font_draw_glyph(RID p_font_rid, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const { + GDVIRTUAL_CALL(_font_draw_glyph, p_font_rid, p_canvas, p_size, p_pos, p_index, p_color); +} + +void TextServerExtension::font_draw_glyph_outline(RID p_font_rid, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color) const { + GDVIRTUAL_CALL(_font_draw_glyph_outline, p_font_rid, p_canvas, p_size, p_outline_size, p_pos, p_index, p_color); +} + +bool TextServerExtension::font_is_language_supported(RID p_font_rid, const String &p_language) const { + bool ret; + if (GDVIRTUAL_CALL(_font_is_language_supported, p_font_rid, p_language, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) { + GDVIRTUAL_CALL(_font_set_language_support_override, p_font_rid, p_language, p_supported); +} + +bool TextServerExtension::font_get_language_support_override(RID p_font_rid, const String &p_language) { + bool ret; + if (GDVIRTUAL_CALL(_font_get_language_support_override, p_font_rid, p_language, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::font_remove_language_support_override(RID p_font_rid, const String &p_language) { + GDVIRTUAL_CALL(_font_remove_language_support_override, p_font_rid, p_language); +} + +Vector<String> TextServerExtension::font_get_language_support_overrides(RID p_font_rid) { + Vector<String> ret; + if (GDVIRTUAL_CALL(_font_get_language_support_overrides, p_font_rid, ret)) { + return ret; + } + return Vector<String>(); +} + +bool TextServerExtension::font_is_script_supported(RID p_font_rid, const String &p_script) const { + bool ret; + if (GDVIRTUAL_CALL(_font_is_script_supported, p_font_rid, p_script, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) { + GDVIRTUAL_CALL(_font_set_script_support_override, p_font_rid, p_script, p_supported); +} + +bool TextServerExtension::font_get_script_support_override(RID p_font_rid, const String &p_script) { + bool ret; + if (GDVIRTUAL_CALL(_font_get_script_support_override, p_font_rid, p_script, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::font_remove_script_support_override(RID p_font_rid, const String &p_script) { + GDVIRTUAL_CALL(_font_remove_script_support_override, p_font_rid, p_script); +} + +Vector<String> TextServerExtension::font_get_script_support_overrides(RID p_font_rid) { + Vector<String> ret; + if (GDVIRTUAL_CALL(_font_get_script_support_overrides, p_font_rid, ret)) { + return ret; + } + return Vector<String>(); +} + +Dictionary TextServerExtension::font_supported_feature_list(RID p_font_rid) const { + Dictionary ret; + if (GDVIRTUAL_CALL(_font_supported_feature_list, p_font_rid, ret)) { + return ret; + } + return Dictionary(); +} + +Dictionary TextServerExtension::font_supported_variation_list(RID p_font_rid) const { + Dictionary ret; + if (GDVIRTUAL_CALL(_font_supported_variation_list, p_font_rid, ret)) { + return ret; + } + return Dictionary(); +} + +float TextServerExtension::font_get_global_oversampling() const { + float ret; + if (GDVIRTUAL_CALL(_font_get_global_oversampling, ret)) { + return ret; + } + return 0.f; +} + +void TextServerExtension::font_set_global_oversampling(float p_oversampling) { + GDVIRTUAL_CALL(_font_set_global_oversampling, p_oversampling); +} + +Vector2 TextServerExtension::get_hex_code_box_size(int p_size, char32_t p_index) const { + Vector2 ret; + if (GDVIRTUAL_CALL(_get_hex_code_box_size, p_size, p_index, ret)) { + return ret; + } + return TextServer::get_hex_code_box_size(p_size, p_index); +} + +void TextServerExtension::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const { + if (!GDVIRTUAL_CALL(_draw_hex_code_box, p_canvas, p_size, p_pos, p_index, p_color)) { + TextServer::draw_hex_code_box(p_canvas, p_size, p_pos, p_index, p_color); + } +} + +/*************************************************************************/ +/* Shaped text buffer interface */ +/*************************************************************************/ + +RID TextServerExtension::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { + RID ret; + if (GDVIRTUAL_CALL(_create_shaped_text, p_direction, p_orientation, ret)) { + return ret; + } + return RID(); +} + +void TextServerExtension::shaped_text_clear(RID p_shaped) { + GDVIRTUAL_CALL(_shaped_text_clear, p_shaped); +} + +void TextServerExtension::shaped_text_set_direction(RID p_shaped, TextServer::Direction p_direction) { + GDVIRTUAL_CALL(_shaped_text_set_direction, p_shaped, p_direction); +} + +TextServer::Direction TextServerExtension::shaped_text_get_direction(RID p_shaped) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_get_direction, p_shaped, ret)) { + return (TextServer::Direction)ret; + } + return TextServer::Direction::DIRECTION_AUTO; +} + +void TextServerExtension::shaped_text_set_orientation(RID p_shaped, TextServer::Orientation p_orientation) { + GDVIRTUAL_CALL(_shaped_text_set_orientation, p_shaped, p_orientation); +} + +TextServer::Orientation TextServerExtension::shaped_text_get_orientation(RID p_shaped) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_get_orientation, p_shaped, ret)) { + return (TextServer::Orientation)ret; + } + return TextServer::Orientation::ORIENTATION_HORIZONTAL; +} + +void TextServerExtension::shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { + GDVIRTUAL_CALL(_shaped_text_set_bidi_override, p_shaped, p_override); +} + +void TextServerExtension::shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) { + GDVIRTUAL_CALL(_shaped_text_set_custom_punctuation, p_shaped, p_punct); +} + +String TextServerExtension::shaped_text_get_custom_punctuation(RID p_shaped) const { + String ret; + if (GDVIRTUAL_CALL(_shaped_text_get_custom_punctuation, p_shaped, ret)) { + return ret; + } + return String(); +} + +void TextServerExtension::shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) { + GDVIRTUAL_CALL(_shaped_text_set_preserve_invalid, p_shaped, p_enabled); +} + +bool TextServerExtension::shaped_text_get_preserve_invalid(RID p_shaped) const { + bool ret; + if (GDVIRTUAL_CALL(_shaped_text_get_preserve_invalid, p_shaped, ret)) { + return ret; + } + return false; +} + +void TextServerExtension::shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) { + GDVIRTUAL_CALL(_shaped_text_set_preserve_control, p_shaped, p_enabled); +} + +bool TextServerExtension::shaped_text_get_preserve_control(RID p_shaped) const { + bool ret; + if (GDVIRTUAL_CALL(_shaped_text_get_preserve_control, p_shaped, ret)) { + return ret; + } + return false; +} + +bool TextServerExtension::shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features, const String &p_language) { + bool ret; + Array fonts; + for (int i = 0; i < p_fonts.size(); i++) { + fonts.push_back(p_fonts[i]); + } + if (GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, fonts, p_size, p_opentype_features, p_language, ret)) { + return ret; + } + return false; +} + +bool TextServerExtension::shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align, int p_length) { + bool ret; + if (GDVIRTUAL_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, ret)) { + return ret; + } + return false; +} + +bool TextServerExtension::shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align) { + bool ret; + if (GDVIRTUAL_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, ret)) { + return ret; + } + return false; +} + +RID TextServerExtension::shaped_text_substr(RID p_shaped, int p_start, int p_length) const { + RID ret; + if (GDVIRTUAL_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret)) { + return ret; + } + return RID(); +} + +RID TextServerExtension::shaped_text_get_parent(RID p_shaped) const { + RID ret; + if (GDVIRTUAL_CALL(_shaped_text_get_parent, p_shaped, ret)) { + return ret; + } + return RID(); +} + +float TextServerExtension::shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t p_jst_flags) { + float ret; + if (GDVIRTUAL_CALL(_shaped_text_fit_to_width, p_shaped, p_width, p_jst_flags, ret)) { + return ret; + } + return 0.f; +} + +float TextServerExtension::shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) { + float ret; + if (GDVIRTUAL_CALL(_shaped_text_tab_align, p_shaped, p_tab_stops, ret)) { + return ret; + } + return 0.f; +} + +bool TextServerExtension::shaped_text_shape(RID p_shaped) { + bool ret; + if (GDVIRTUAL_CALL(_shaped_text_shape, p_shaped, ret)) { + return ret; + } + return false; +} + +bool TextServerExtension::shaped_text_update_breaks(RID p_shaped) { + bool ret; + if (GDVIRTUAL_CALL(_shaped_text_update_breaks, p_shaped, ret)) { + return ret; + } + return false; +} + +bool TextServerExtension::shaped_text_update_justification_ops(RID p_shaped) { + bool ret; + if (GDVIRTUAL_CALL(_shaped_text_update_justification_ops, p_shaped, ret)) { + return ret; + } + return false; +} + +bool TextServerExtension::shaped_text_is_ready(RID p_shaped) const { + bool ret; + if (GDVIRTUAL_CALL(_shaped_text_is_ready, p_shaped, ret)) { + return ret; + } + return false; +} + +const Glyph *TextServerExtension::shaped_text_get_glyphs(RID p_shaped) const { + const Glyph *ret; + if (GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, &ret)) { + return ret; + } + return nullptr; +} + +const Glyph *TextServerExtension::shaped_text_sort_logical(RID p_shaped) { + const Glyph *ret; + if (GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, &ret)) { + return ret; + } + return nullptr; +} + +int TextServerExtension::shaped_text_get_glyph_count(RID p_shaped) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_get_glyph_count, p_shaped, ret)) { + return ret; + } + return 0; +} + +Vector2i TextServerExtension::shaped_text_get_range(RID p_shaped) const { + Vector2i ret; + if (GDVIRTUAL_CALL(_shaped_text_get_range, p_shaped, ret)) { + return ret; + } + return Vector2i(); +} + +PackedInt32Array TextServerExtension::shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint16_t p_break_flags) const { + PackedInt32Array ret; + if (GDVIRTUAL_CALL(_shaped_text_get_line_breaks_adv, p_shaped, p_width, p_start, p_once, p_break_flags, ret)) { + return ret; + } + return TextServer::shaped_text_get_line_breaks_adv(p_shaped, p_width, p_start, p_once, p_break_flags); +} + +PackedInt32Array TextServerExtension::shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start, uint16_t p_break_flags) const { + PackedInt32Array ret; + if (GDVIRTUAL_CALL(_shaped_text_get_line_breaks, p_shaped, p_width, p_start, p_break_flags, ret)) { + return ret; + } + return TextServer::shaped_text_get_line_breaks(p_shaped, p_width, p_start, p_break_flags); +} + +PackedInt32Array TextServerExtension::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const { + PackedInt32Array ret; + if (GDVIRTUAL_CALL(_shaped_text_get_word_breaks, p_shaped, p_grapheme_flags, ret)) { + return ret; + } + return TextServer::shaped_text_get_word_breaks(p_shaped, p_grapheme_flags); +} + +int TextServerExtension::shaped_text_get_trim_pos(RID p_shaped) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_get_trim_pos, p_shaped, ret)) { + return ret; + } + return -1; +} + +int TextServerExtension::shaped_text_get_ellipsis_pos(RID p_shaped) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_pos, p_shaped, ret)) { + return ret; + } + return -1; +} + +const Glyph *TextServerExtension::shaped_text_get_ellipsis_glyphs(RID p_shaped) const { + const Glyph *ret; + if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, &ret)) { + return ret; + } + return nullptr; +} + +int TextServerExtension::shaped_text_get_ellipsis_glyph_count(RID p_shaped) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyph_count, p_shaped, ret)) { + return ret; + } + return -1; +} + +void TextServerExtension::shaped_text_overrun_trim_to_width(RID p_shaped_line, float p_width, uint16_t p_trim_flags) { + GDVIRTUAL_CALL(_shaped_text_overrun_trim_to_width, p_shaped_line, p_width, p_trim_flags); +} + +Array TextServerExtension::shaped_text_get_objects(RID p_shaped) const { + Array ret; + if (GDVIRTUAL_CALL(_shaped_text_get_objects, p_shaped, ret)) { + return ret; + } + return Array(); +} + +Rect2 TextServerExtension::shaped_text_get_object_rect(RID p_shaped, Variant p_key) const { + Rect2 ret; + if (GDVIRTUAL_CALL(_shaped_text_get_object_rect, p_shaped, p_key, ret)) { + return ret; + } + return Rect2(); +} + +Size2 TextServerExtension::shaped_text_get_size(RID p_shaped) const { + Size2 ret; + if (GDVIRTUAL_CALL(_shaped_text_get_size, p_shaped, ret)) { + return ret; + } + return Size2(); +} + +float TextServerExtension::shaped_text_get_ascent(RID p_shaped) const { + float ret; + if (GDVIRTUAL_CALL(_shaped_text_get_ascent, p_shaped, ret)) { + return ret; + } + return 0.f; +} + +float TextServerExtension::shaped_text_get_descent(RID p_shaped) const { + float ret; + if (GDVIRTUAL_CALL(_shaped_text_get_descent, p_shaped, ret)) { + return ret; + } + return 0.f; +} + +float TextServerExtension::shaped_text_get_width(RID p_shaped) const { + float ret; + if (GDVIRTUAL_CALL(_shaped_text_get_width, p_shaped, ret)) { + return ret; + } + return 0.f; +} + +float TextServerExtension::shaped_text_get_underline_position(RID p_shaped) const { + float ret; + if (GDVIRTUAL_CALL(_shaped_text_get_underline_position, p_shaped, ret)) { + return ret; + } + return 0.f; +} + +float TextServerExtension::shaped_text_get_underline_thickness(RID p_shaped) const { + float ret; + if (GDVIRTUAL_CALL(_shaped_text_get_underline_thickness, p_shaped, ret)) { + return ret; + } + return 0.f; +} + +TextServer::Direction TextServerExtension::shaped_text_get_dominant_direction_in_range(RID p_shaped, int p_start, int p_end) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_get_dominant_direction_in_range, p_shaped, p_start, p_end, ret)) { + return (TextServer::Direction)ret; + } + return TextServer::shaped_text_get_dominant_direction_in_range(p_shaped, p_start, p_end); +} + +CaretInfo TextServerExtension::shaped_text_get_carets(RID p_shaped, int p_position) const { + CaretInfo ret; + if (GDVIRTUAL_CALL(_shaped_text_get_carets, p_shaped, p_position, &ret)) { + return ret; + } + return TextServer::shaped_text_get_carets(p_shaped, p_position); +} + +Vector<Vector2> TextServerExtension::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const { + Vector<Vector2> ret; + if (GDVIRTUAL_CALL(_shaped_text_get_selection, p_shaped, p_start, p_end, ret)) { + return ret; + } + return TextServer::shaped_text_get_selection(p_shaped, p_start, p_end); +} + +int TextServerExtension::shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_hit_test_grapheme, p_shaped, p_coords, ret)) { + return ret; + } + return TextServer::shaped_text_hit_test_grapheme(p_shaped, p_coords); +} + +int TextServerExtension::shaped_text_hit_test_position(RID p_shaped, float p_coords) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_hit_test_position, p_shaped, p_coords, ret)) { + return ret; + } + return TextServer::shaped_text_hit_test_position(p_shaped, p_coords); +} + +void TextServerExtension::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, const Color &p_color) const { + if (GDVIRTUAL_CALL(_shaped_text_draw, p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_color)) { + return; + } + TextServer::shaped_text_draw(p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_color); +} + +void TextServerExtension::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l, float p_clip_r, int p_outline_size, const Color &p_color) const { + if (GDVIRTUAL_CALL(_shaped_text_draw_outline, p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color)) { + return; + } + shaped_text_draw_outline(p_shaped, p_canvas, p_pos, p_clip_l, p_clip_r, p_outline_size, p_color); +} + +Vector2 TextServerExtension::shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const { + Vector2 ret; + if (GDVIRTUAL_CALL(_shaped_text_get_grapheme_bounds, p_shaped, p_pos, ret)) { + return ret; + } + return TextServer::shaped_text_get_grapheme_bounds(p_shaped, p_pos); +} + +int TextServerExtension::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_next_grapheme_pos, p_shaped, p_pos, ret)) { + return ret; + } + return TextServer::shaped_text_next_grapheme_pos(p_shaped, p_pos); +} + +int TextServerExtension::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const { + int ret; + if (GDVIRTUAL_CALL(_shaped_text_prev_grapheme_pos, p_shaped, p_pos, ret)) { + return ret; + } + return TextServer::shaped_text_prev_grapheme_pos(p_shaped, p_pos); +} + +String TextServerExtension::format_number(const String &p_string, const String &p_language) const { + String ret; + if (GDVIRTUAL_CALL(_format_number, p_string, p_language, ret)) { + return ret; + } + return TextServer::format_number(p_string, p_language); +} + +String TextServerExtension::parse_number(const String &p_string, const String &p_language) const { + String ret; + if (GDVIRTUAL_CALL(_parse_number, p_string, p_language, ret)) { + return ret; + } + return TextServer::parse_number(p_string, p_language); +} + +String TextServerExtension::percent_sign(const String &p_language) const { + String ret; + if (GDVIRTUAL_CALL(_percent_sign, p_language, ret)) { + return ret; + } + return TextServer::percent_sign(p_language); +} + +TextServerExtension::TextServerExtension() { + //NOP +} + +TextServerExtension::~TextServerExtension() { + //NOP +} diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h new file mode 100644 index 0000000000..a2dbd25e05 --- /dev/null +++ b/servers/text/text_server_extension.h @@ -0,0 +1,449 @@ +/*************************************************************************/ +/* text_server_extension.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef TEXT_SERVER_EXTENSION_H +#define TEXT_SERVER_EXTENSION_H + +#include "core/object/gdvirtual.gen.inc" +#include "core/object/script_language.h" +#include "core/os/thread_safe.h" +#include "core/variant/native_ptr.h" +#include "servers/text_server.h" + +class TextServerExtension : public TextServer { + GDCLASS(TextServerExtension, TextServer); + +protected: + _THREAD_SAFE_CLASS_ + + static void _bind_methods(); + +public: + virtual bool has_feature(Feature p_feature) const override; + virtual String get_name() const override; + virtual uint32_t get_features() const override; + GDVIRTUAL1RC(bool, _has_feature, Feature); + GDVIRTUAL0RC(String, _get_name); + GDVIRTUAL0RC(uint32_t, _get_features); + + virtual void free(RID p_rid) override; + virtual bool has(RID p_rid) override; + virtual bool load_support_data(const String &p_filename) override; + GDVIRTUAL1(_free, RID); + GDVIRTUAL1R(bool, _has, RID); + GDVIRTUAL1R(bool, _load_support_data, const String &); + + virtual String get_support_data_filename() const override; + virtual String get_support_data_info() const override; + virtual bool save_support_data(const String &p_filename) const override; + GDVIRTUAL0RC(String, _get_support_data_filename); + GDVIRTUAL0RC(String, _get_support_data_info); + GDVIRTUAL1RC(bool, _save_support_data, const String &); + + virtual bool is_locale_right_to_left(const String &p_locale) const override; + GDVIRTUAL1RC(bool, _is_locale_right_to_left, const String &); + + virtual int32_t name_to_tag(const String &p_name) const override; + virtual String tag_to_name(int32_t p_tag) const override; + GDVIRTUAL1RC(int32_t, _name_to_tag, const String &); + GDVIRTUAL1RC(String, _tag_to_name, int32_t); + + /* Font interface */ + virtual RID create_font() override; + GDVIRTUAL0R(RID, _create_font); + + virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) override; + virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) override; + GDVIRTUAL2(_font_set_data, RID, const PackedByteArray &); + GDVIRTUAL3(_font_set_data_ptr, RID, GDNativeConstPtr<const uint8_t>, uint64_t); + + virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) override; + virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_style, RID, uint32_t); + GDVIRTUAL1RC(uint32_t, _font_get_style, RID); + + virtual void font_set_name(RID p_font_rid, const String &p_name) override; + virtual String font_get_name(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_name, RID, const String &); + GDVIRTUAL1RC(String, _font_get_name, RID); + + virtual void font_set_style_name(RID p_font_rid, const String &p_name) override; + virtual String font_get_style_name(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_style_name, RID, const String &); + GDVIRTUAL1RC(String, _font_get_style_name, RID); + + virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) override; + virtual bool font_is_antialiased(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_antialiased, RID, bool); + GDVIRTUAL1RC(bool, _font_is_antialiased, RID); + + virtual void font_set_multichannel_signed_distance_field(RID p_font_rid, bool p_msdf) override; + virtual bool font_is_multichannel_signed_distance_field(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_multichannel_signed_distance_field, RID, bool); + GDVIRTUAL1RC(bool, _font_is_multichannel_signed_distance_field, RID); + + virtual void font_set_msdf_pixel_range(RID p_font_rid, int p_msdf_pixel_range) override; + virtual int font_get_msdf_pixel_range(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_msdf_pixel_range, RID, int); + GDVIRTUAL1RC(int, _font_get_msdf_pixel_range, RID); + + virtual void font_set_msdf_size(RID p_font_rid, int p_msdf_size) override; + virtual int font_get_msdf_size(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_msdf_size, RID, int); + GDVIRTUAL1RC(int, _font_get_msdf_size, RID); + + virtual void font_set_fixed_size(RID p_font_rid, int p_fixed_size) override; + virtual int font_get_fixed_size(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_fixed_size, RID, int); + GDVIRTUAL1RC(int, _font_get_fixed_size, RID); + + virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) override; + virtual bool font_is_force_autohinter(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_force_autohinter, RID, bool); + GDVIRTUAL1RC(bool, _font_is_force_autohinter, RID); + + virtual void font_set_hinting(RID p_font_rid, Hinting p_hinting) override; + virtual Hinting font_get_hinting(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_hinting, RID, Hinting); + GDVIRTUAL1RC(/*Hinting*/ int, _font_get_hinting, RID); + + virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) override; + virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_variation_coordinates, RID, Dictionary); + GDVIRTUAL1RC(Dictionary, _font_get_variation_coordinates, RID); + + virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) override; + virtual float font_get_oversampling(RID p_font_rid) const override; + GDVIRTUAL2(_font_set_oversampling, RID, float); + GDVIRTUAL1RC(float, _font_get_oversampling, RID); + + virtual Array font_get_size_cache_list(RID p_font_rid) const override; + virtual void font_clear_size_cache(RID p_font_rid) override; + virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) override; + GDVIRTUAL1RC(Array, _font_get_size_cache_list, RID); + GDVIRTUAL1(_font_clear_size_cache, RID); + GDVIRTUAL2(_font_remove_size_cache, RID, const Vector2i &); + + virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) override; + virtual float font_get_ascent(RID p_font_rid, int p_size) const override; + GDVIRTUAL3(_font_set_ascent, RID, int, float); + GDVIRTUAL2RC(float, _font_get_ascent, RID, int); + + virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) override; + virtual float font_get_descent(RID p_font_rid, int p_size) const override; + GDVIRTUAL3(_font_set_descent, RID, int, float); + GDVIRTUAL2RC(float, _font_get_descent, RID, int); + + virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) override; + virtual float font_get_underline_position(RID p_font_rid, int p_size) const override; + GDVIRTUAL3(_font_set_underline_position, RID, int, float); + GDVIRTUAL2RC(float, _font_get_underline_position, RID, int); + + virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) override; + virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const override; + GDVIRTUAL3(_font_set_underline_thickness, RID, int, float); + GDVIRTUAL2RC(float, _font_get_underline_thickness, RID, int); + + virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) override; + virtual float font_get_scale(RID p_font_rid, int p_size) const override; + GDVIRTUAL3(_font_set_scale, RID, int, float); + GDVIRTUAL2RC(float, _font_get_scale, RID, int); + + virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) override; + virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const override; + GDVIRTUAL4(_font_set_spacing, RID, int, SpacingType, int); + GDVIRTUAL3RC(int, _font_get_spacing, RID, int, SpacingType); + + virtual int font_get_texture_count(RID p_font_rid, const Vector2i &p_size) const override; + virtual void font_clear_textures(RID p_font_rid, const Vector2i &p_size) override; + virtual void font_remove_texture(RID p_font_rid, const Vector2i &p_size, int p_texture_index) override; + GDVIRTUAL2RC(int, _font_get_texture_count, RID, const Vector2i &); + GDVIRTUAL2(_font_clear_textures, RID, const Vector2i &); + GDVIRTUAL3(_font_remove_texture, RID, const Vector2i &, int); + + virtual void font_set_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const Ref<Image> &p_image) override; + virtual Ref<Image> font_get_texture_image(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override; + GDVIRTUAL4(_font_set_texture_image, RID, const Vector2i &, int, const Ref<Image> &); + GDVIRTUAL3RC(Ref<Image>, _font_get_texture_image, RID, const Vector2i &, int); + + virtual void font_set_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index, const PackedInt32Array &p_offset) override; + virtual PackedInt32Array font_get_texture_offsets(RID p_font_rid, const Vector2i &p_size, int p_texture_index) const override; + GDVIRTUAL4(_font_set_texture_offsets, RID, const Vector2i &, int, const PackedInt32Array &); + GDVIRTUAL3RC(PackedInt32Array, _font_get_texture_offsets, RID, const Vector2i &, int); + + virtual Array font_get_glyph_list(RID p_font_rid, const Vector2i &p_size) const override; + virtual void font_clear_glyphs(RID p_font_rid, const Vector2i &p_size) override; + virtual void font_remove_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) override; + GDVIRTUAL2RC(Array, _font_get_glyph_list, RID, const Vector2i &); + GDVIRTUAL2(_font_clear_glyphs, RID, const Vector2i &); + GDVIRTUAL3(_font_remove_glyph, RID, const Vector2i &, int32_t); + + virtual Vector2 font_get_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph) const override; + virtual void font_set_glyph_advance(RID p_font_rid, int p_size, int32_t p_glyph, const Vector2 &p_advance) override; + GDVIRTUAL3RC(Vector2, _font_get_glyph_advance, RID, int, int32_t); + GDVIRTUAL4(_font_set_glyph_advance, RID, int, int32_t, const Vector2 &); + + virtual Vector2 font_get_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; + virtual void font_set_glyph_offset(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_offset) override; + GDVIRTUAL3RC(Vector2, _font_get_glyph_offset, RID, const Vector2i &, int32_t); + GDVIRTUAL4(_font_set_glyph_offset, RID, const Vector2i &, int32_t, const Vector2 &); + + virtual Vector2 font_get_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; + virtual void font_set_glyph_size(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Vector2 &p_gl_size) override; + GDVIRTUAL3RC(Vector2, _font_get_glyph_size, RID, const Vector2i &, int32_t); + GDVIRTUAL4(_font_set_glyph_size, RID, const Vector2i &, int32_t, const Vector2 &); + + virtual Rect2 font_get_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; + virtual void font_set_glyph_uv_rect(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, const Rect2 &p_uv_rect) override; + GDVIRTUAL3RC(Rect2, _font_get_glyph_uv_rect, RID, const Vector2i &, int32_t); + GDVIRTUAL4(_font_set_glyph_uv_rect, RID, const Vector2i &, int32_t, const Rect2 &); + + virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const override; + virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) override; + GDVIRTUAL3RC(int, _font_get_glyph_texture_idx, RID, const Vector2i &, int32_t); + GDVIRTUAL4(_font_set_glyph_texture_idx, RID, const Vector2i &, int32_t, int); + + virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const override; + GDVIRTUAL3RC(Dictionary, _font_get_glyph_contours, RID, int, int32_t); + + virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const override; + virtual void font_clear_kerning_map(RID p_font_rid, int p_size) override; + virtual void font_remove_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) override; + GDVIRTUAL2RC(Array, _font_get_kerning_list, RID, int); + GDVIRTUAL2(_font_clear_kerning_map, RID, int); + GDVIRTUAL3(_font_remove_kerning, RID, int, const Vector2i &); + + virtual void font_set_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair, const Vector2 &p_kerning) override; + virtual Vector2 font_get_kerning(RID p_font_rid, int p_size, const Vector2i &p_glyph_pair) const override; + GDVIRTUAL4(_font_set_kerning, RID, int, const Vector2i &, const Vector2 &); + GDVIRTUAL3RC(Vector2, _font_get_kerning, RID, int, const Vector2i &); + + virtual int32_t font_get_glyph_index(RID p_font_rid, int p_size, char32_t p_char, char32_t p_variation_selector = 0) const override; + GDVIRTUAL4RC(int32_t, _font_get_glyph_index, RID, int, char32_t, char32_t); + + virtual bool font_has_char(RID p_font_rid, char32_t p_char) const override; + virtual String font_get_supported_chars(RID p_font_rid) const override; + GDVIRTUAL2RC(bool, _font_has_char, RID, char32_t); + GDVIRTUAL1RC(String, _font_get_supported_chars, RID); + + virtual void font_render_range(RID p_font, const Vector2i &p_size, char32_t p_start, char32_t p_end) override; + virtual void font_render_glyph(RID p_font_rid, const Vector2i &p_size, int32_t p_index) override; + GDVIRTUAL4(_font_render_range, RID, const Vector2i &, char32_t, char32_t); + GDVIRTUAL3(_font_render_glyph, RID, const Vector2i &, int32_t); + + virtual void font_draw_glyph(RID p_font, RID p_canvas, int p_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + virtual void font_draw_glyph_outline(RID p_font, RID p_canvas, int p_size, int p_outline_size, const Vector2 &p_pos, int32_t p_index, const Color &p_color = Color(1, 1, 1)) const override; + GDVIRTUAL6C(_font_draw_glyph, RID, RID, int, const Vector2 &, int32_t, const Color &); + GDVIRTUAL7C(_font_draw_glyph_outline, RID, RID, int, int, const Vector2 &, int32_t, const Color &); + + virtual bool font_is_language_supported(RID p_font_rid, const String &p_language) const override; + virtual void font_set_language_support_override(RID p_font_rid, const String &p_language, bool p_supported) override; + virtual bool font_get_language_support_override(RID p_font_rid, const String &p_language) override; + virtual void font_remove_language_support_override(RID p_font_rid, const String &p_language) override; + virtual Vector<String> font_get_language_support_overrides(RID p_font_rid) override; + GDVIRTUAL2RC(bool, _font_is_language_supported, RID, const String &); + GDVIRTUAL3(_font_set_language_support_override, RID, const String &, bool); + GDVIRTUAL2R(bool, _font_get_language_support_override, RID, const String &); + GDVIRTUAL2(_font_remove_language_support_override, RID, const String &); + GDVIRTUAL1R(Vector<String>, _font_get_language_support_overrides, RID); + + virtual bool font_is_script_supported(RID p_font_rid, const String &p_script) const override; + virtual void font_set_script_support_override(RID p_font_rid, const String &p_script, bool p_supported) override; + virtual bool font_get_script_support_override(RID p_font_rid, const String &p_script) override; + virtual void font_remove_script_support_override(RID p_font_rid, const String &p_script) override; + virtual Vector<String> font_get_script_support_overrides(RID p_font_rid) override; + GDVIRTUAL2RC(bool, _font_is_script_supported, RID, const String &); + GDVIRTUAL3(_font_set_script_support_override, RID, const String &, bool); + GDVIRTUAL2R(bool, _font_get_script_support_override, RID, const String &); + GDVIRTUAL2(_font_remove_script_support_override, RID, const String &); + GDVIRTUAL1R(Vector<String>, _font_get_script_support_overrides, RID); + + virtual Dictionary font_supported_feature_list(RID p_font_rid) const override; + virtual Dictionary font_supported_variation_list(RID p_font_rid) const override; + GDVIRTUAL1RC(Dictionary, _font_supported_feature_list, RID); + GDVIRTUAL1RC(Dictionary, _font_supported_variation_list, RID); + + virtual float font_get_global_oversampling() const override; + virtual void font_set_global_oversampling(float p_oversampling) override; + GDVIRTUAL0RC(float, _font_get_global_oversampling); + GDVIRTUAL1(_font_set_global_oversampling, float); + + virtual Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const override; + virtual void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const override; + GDVIRTUAL2RC(Vector2, _get_hex_code_box_size, int, char32_t); + GDVIRTUAL5C(_draw_hex_code_box, RID, int, const Vector2 &, char32_t, const Color &); + + /* Shaped text buffer interface */ + + virtual RID create_shaped_text(Direction p_direction = DIRECTION_AUTO, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; + GDVIRTUAL2R(RID, _create_shaped_text, Direction, Orientation); + + virtual void shaped_text_clear(RID p_shaped) override; + GDVIRTUAL1(_shaped_text_clear, RID); + + virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) override; + virtual Direction shaped_text_get_direction(RID p_shaped) const override; + GDVIRTUAL2(_shaped_text_set_direction, RID, Direction); + GDVIRTUAL1RC(/*Direction*/ int, _shaped_text_get_direction, RID); + + virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) override; + GDVIRTUAL2(_shaped_text_set_bidi_override, RID, const Array &); + + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) override; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const override; + GDVIRTUAL2(_shaped_text_set_custom_punctuation, RID, String); + GDVIRTUAL1RC(String, _shaped_text_get_custom_punctuation, RID); + + virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) override; + virtual Orientation shaped_text_get_orientation(RID p_shaped) const override; + GDVIRTUAL2(_shaped_text_set_orientation, RID, Orientation); + GDVIRTUAL1RC(/*Orientation*/ int, _shaped_text_get_orientation, RID); + + virtual void shaped_text_set_preserve_invalid(RID p_shaped, bool p_enabled) override; + virtual bool shaped_text_get_preserve_invalid(RID p_shaped) const override; + GDVIRTUAL2(_shaped_text_set_preserve_invalid, RID, bool); + GDVIRTUAL1RC(bool, _shaped_text_get_preserve_invalid, RID); + + virtual void shaped_text_set_preserve_control(RID p_shaped, bool p_enabled) override; + virtual bool shaped_text_get_preserve_control(RID p_shaped) const override; + GDVIRTUAL2(_shaped_text_set_preserve_control, RID, bool); + GDVIRTUAL1RC(bool, _shaped_text_get_preserve_control, RID); + + virtual bool shaped_text_add_string(RID p_shaped, const String &p_text, const Vector<RID> &p_fonts, int p_size, const Dictionary &p_opentype_features = Dictionary(), const String &p_language = "") override; + virtual bool shaped_text_add_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER, int p_length = 1) override; + virtual bool shaped_text_resize_object(RID p_shaped, Variant p_key, const Size2 &p_size, InlineAlign p_inline_align = INLINE_ALIGN_CENTER) override; + GDVIRTUAL6R(bool, _shaped_text_add_string, RID, const String &, const Array &, int, const Dictionary &, const String &); + GDVIRTUAL5R(bool, _shaped_text_add_object, RID, Variant, const Size2 &, InlineAlign, int); + GDVIRTUAL4R(bool, _shaped_text_resize_object, RID, Variant, const Size2 &, InlineAlign); + + virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const override; + virtual RID shaped_text_get_parent(RID p_shaped) const override; + GDVIRTUAL3RC(RID, _shaped_text_substr, RID, int, int); + GDVIRTUAL1RC(RID, _shaped_text_get_parent, RID); + + virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) override; + virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) override; + GDVIRTUAL3R(float, _shaped_text_fit_to_width, RID, float, uint16_t); + GDVIRTUAL2R(float, _shaped_text_tab_align, RID, const PackedFloat32Array &); + + virtual bool shaped_text_shape(RID p_shaped) override; + virtual bool shaped_text_update_breaks(RID p_shaped) override; + virtual bool shaped_text_update_justification_ops(RID p_shaped) override; + GDVIRTUAL1R(bool, _shaped_text_shape, RID); + GDVIRTUAL1R(bool, _shaped_text_update_breaks, RID); + GDVIRTUAL1R(bool, _shaped_text_update_justification_ops, RID); + + virtual bool shaped_text_is_ready(RID p_shaped) const override; + GDVIRTUAL1RC(bool, _shaped_text_is_ready, RID); + + virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const override; + virtual const Glyph *shaped_text_sort_logical(RID p_shaped) override; + virtual int shaped_text_get_glyph_count(RID p_shaped) const override; + GDVIRTUAL2C(_shaped_text_get_glyphs, RID, GDNativePtr<const Glyph *>); + GDVIRTUAL2(_shaped_text_sort_logical, RID, GDNativePtr<const Glyph *>); + GDVIRTUAL1RC(int, _shaped_text_get_glyph_count, RID); + + virtual Vector2i shaped_text_get_range(RID p_shaped) const override; + GDVIRTUAL1RC(Vector2i, _shaped_text_get_range, RID); + + virtual PackedInt32Array shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start = 0, bool p_once = true, uint16_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override; + virtual PackedInt32Array shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint16_t p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const override; + virtual PackedInt32Array shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const override; + GDVIRTUAL5RC(PackedInt32Array, _shaped_text_get_line_breaks_adv, RID, const PackedFloat32Array &, int, bool, uint16_t); + GDVIRTUAL4RC(PackedInt32Array, _shaped_text_get_line_breaks, RID, float, int, uint16_t); + GDVIRTUAL2RC(PackedInt32Array, _shaped_text_get_word_breaks, RID, int); + + virtual int shaped_text_get_trim_pos(RID p_shaped) const override; + virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const override; + virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const override; + virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const override; + GDVIRTUAL1RC(int, _shaped_text_get_trim_pos, RID); + GDVIRTUAL1RC(int, _shaped_text_get_ellipsis_pos, RID); + GDVIRTUAL2C(_shaped_text_get_ellipsis_glyphs, RID, GDNativePtr<const Glyph *>); + GDVIRTUAL1RC(int, _shaped_text_get_ellipsis_glyph_count, RID); + + virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) override; + GDVIRTUAL3(_shaped_text_overrun_trim_to_width, RID, float, uint16_t); + + virtual Array shaped_text_get_objects(RID p_shaped) const override; + virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const override; + GDVIRTUAL1RC(Array, _shaped_text_get_objects, RID); + GDVIRTUAL2RC(Rect2, _shaped_text_get_object_rect, RID, Variant); + + virtual Size2 shaped_text_get_size(RID p_shaped) const override; + virtual float shaped_text_get_ascent(RID p_shaped) const override; + virtual float shaped_text_get_descent(RID p_shaped) const override; + virtual float shaped_text_get_width(RID p_shaped) const override; + virtual float shaped_text_get_underline_position(RID p_shaped) const override; + virtual float shaped_text_get_underline_thickness(RID p_shaped) const override; + GDVIRTUAL1RC(Size2, _shaped_text_get_size, RID); + GDVIRTUAL1RC(float, _shaped_text_get_ascent, RID); + GDVIRTUAL1RC(float, _shaped_text_get_descent, RID); + GDVIRTUAL1RC(float, _shaped_text_get_width, RID); + GDVIRTUAL1RC(float, _shaped_text_get_underline_position, RID); + GDVIRTUAL1RC(float, _shaped_text_get_underline_thickness, RID); + + virtual Direction shaped_text_get_dominant_direction_in_range(RID p_shaped, int p_start, int p_end) const override; + GDVIRTUAL3RC(int, _shaped_text_get_dominant_direction_in_range, RID, int, int); + + virtual CaretInfo shaped_text_get_carets(RID p_shaped, int p_position) const override; + virtual Vector<Vector2> shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const override; + GDVIRTUAL3C(_shaped_text_get_carets, RID, int, GDNativePtr<CaretInfo>); + GDVIRTUAL3RC(Vector<Vector2>, _shaped_text_get_selection, RID, int, int); + + virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const override; + virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const override; + GDVIRTUAL2RC(int, _shaped_text_hit_test_grapheme, RID, float); + GDVIRTUAL2RC(int, _shaped_text_hit_test_position, RID, float); + + virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const override; + virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const override; + GDVIRTUAL6C(_shaped_text_draw, RID, RID, const Vector2 &, float, float, const Color &); + GDVIRTUAL7C(_shaped_text_draw_outline, RID, RID, const Vector2 &, float, float, int, const Color &); + + virtual Vector2 shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const override; + virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const override; + virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const override; + GDVIRTUAL2RC(Vector2, _shaped_text_get_grapheme_bounds, RID, int); + GDVIRTUAL2RC(int, _shaped_text_next_grapheme_pos, RID, int); + GDVIRTUAL2RC(int, _shaped_text_prev_grapheme_pos, RID, int); + + virtual String format_number(const String &p_string, const String &p_language = "") const override; + virtual String parse_number(const String &p_string, const String &p_language = "") const override; + virtual String percent_sign(const String &p_language = "") const override; + GDVIRTUAL2RC(String, _format_number, const String &, const String &); + GDVIRTUAL2RC(String, _parse_number, const String &, const String &); + GDVIRTUAL1RC(String, _percent_sign, const String &); + + TextServerExtension(); + ~TextServerExtension(); +}; + +#endif // TEXT_SERVER_EXTENSION_H diff --git a/servers/text_server.cpp b/servers/text_server.cpp index 2f343e8f80..3b71dc1d92 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -29,125 +29,107 @@ /*************************************************************************/ #include "servers/text_server.h" -#include "scene/main/canvas_item.h" +#include "servers/rendering_server.h" TextServerManager *TextServerManager::singleton = nullptr; -TextServer *TextServerManager::server = nullptr; -TextServerManager::TextServerCreate TextServerManager::server_create_functions[TextServerManager::MAX_SERVERS]; -int TextServerManager::server_create_count = 0; void TextServerManager::_bind_methods() { - ClassDB::bind_method(D_METHOD("get_interface_count"), &TextServerManager::_get_interface_count); - ClassDB::bind_method(D_METHOD("get_interface_name", "index"), &TextServerManager::_get_interface_name); - ClassDB::bind_method(D_METHOD("get_interface_features", "index"), &TextServerManager::_get_interface_features); - ClassDB::bind_method(D_METHOD("get_interface", "index"), &TextServerManager::_get_interface); - ClassDB::bind_method(D_METHOD("get_interfaces"), &TextServerManager::_get_interfaces); - ClassDB::bind_method(D_METHOD("find_interface", "name"), &TextServerManager::_find_interface); - - ClassDB::bind_method(D_METHOD("set_primary_interface", "index"), &TextServerManager::_set_primary_interface); - ClassDB::bind_method(D_METHOD("get_primary_interface"), &TextServerManager::_get_primary_interface); + ClassDB::bind_method(D_METHOD("add_interface", "interface"), &TextServerManager::add_interface); + ClassDB::bind_method(D_METHOD("get_interface_count"), &TextServerManager::get_interface_count); + ClassDB::bind_method(D_METHOD("remove_interface", "interface"), &TextServerManager::remove_interface); + ClassDB::bind_method(D_METHOD("get_interface", "idx"), &TextServerManager::get_interface); + ClassDB::bind_method(D_METHOD("get_interfaces"), &TextServerManager::get_interfaces); + ClassDB::bind_method(D_METHOD("find_interface", "name"), &TextServerManager::find_interface); + + ClassDB::bind_method(D_METHOD("set_primary_interface", "index"), &TextServerManager::set_primary_interface); + ClassDB::bind_method(D_METHOD("get_primary_interface"), &TextServerManager::get_primary_interface); + + ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING_NAME, "interface_name"))); + ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING_NAME, "interface_name"))); } -void TextServerManager::register_create_function(const String &p_name, uint32_t p_features, TextServerManager::CreateFunction p_function, void *p_user_data) { - ERR_FAIL_COND(server_create_count == MAX_SERVERS); - server_create_functions[server_create_count].name = p_name; - server_create_functions[server_create_count].create_function = p_function; - server_create_functions[server_create_count].user_data = p_user_data; - server_create_functions[server_create_count].features = p_features; - server_create_count++; -} +void TextServerManager::add_interface(const Ref<TextServer> &p_interface) { + ERR_FAIL_COND(p_interface.is_null()); -int TextServerManager::get_interface_count() { - return server_create_count; -} + for (int i = 0; i < interfaces.size(); i++) { + if (interfaces[i] == p_interface) { + ERR_PRINT("TextServer: Interface was already added."); + return; + }; + }; -String TextServerManager::get_interface_name(int p_index) { - ERR_FAIL_INDEX_V(p_index, server_create_count, String()); - return server_create_functions[p_index].name; + interfaces.push_back(p_interface); + print_verbose("TextServer: Added interface \"" + p_interface->get_name() + "\""); + emit_signal(SNAME("interface_added"), p_interface->get_name()); } -uint32_t TextServerManager::get_interface_features(int p_index) { - ERR_FAIL_INDEX_V(p_index, server_create_count, 0); - return server_create_functions[p_index].features; -} +void TextServerManager::remove_interface(const Ref<TextServer> &p_interface) { + ERR_FAIL_COND(p_interface.is_null()); + ERR_FAIL_COND_MSG(p_interface == primary_interface, "TextServer: Can't remove primary interface."); -TextServer *TextServerManager::initialize(int p_index, Error &r_error) { - ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr); - if (server_create_functions[p_index].instance == nullptr) { - server_create_functions[p_index].instance = server_create_functions[p_index].create_function(r_error, server_create_functions[p_index].user_data); - if (server_create_functions[p_index].instance != nullptr) { - server_create_functions[p_index].instance->load_support_data(""); // Try loading default data. - } - } - if (server_create_functions[p_index].instance != nullptr) { - server = server_create_functions[p_index].instance; - if (OS::get_singleton()->get_main_loop()) { - OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED); - } - } - return server_create_functions[p_index].instance; -} - -TextServer *TextServerManager::get_primary_interface() { - return server; -} + int idx = -1; + for (int i = 0; i < interfaces.size(); i++) { + if (interfaces[i] == p_interface) { + idx = i; + break; + }; + }; -int TextServerManager::_get_interface_count() const { - return server_create_count; + ERR_FAIL_COND(idx == -1); + print_verbose("TextServer: Removed interface \"" + p_interface->get_name() + "\""); + emit_signal(SNAME("interface_removed"), p_interface->get_name()); + interfaces.remove_at(idx); } -String TextServerManager::_get_interface_name(int p_index) const { - return get_interface_name(p_index); +int TextServerManager::get_interface_count() const { + return interfaces.size(); } -uint32_t TextServerManager::_get_interface_features(int p_index) const { - return get_interface_features(p_index); +Ref<TextServer> TextServerManager::get_interface(int p_index) const { + ERR_FAIL_INDEX_V(p_index, interfaces.size(), nullptr); + return interfaces[p_index]; } -TextServer *TextServerManager::_get_interface(int p_index) const { - ERR_FAIL_INDEX_V(p_index, server_create_count, nullptr); - if (server_create_functions[p_index].instance == nullptr) { - Error error; - server_create_functions[p_index].instance = server_create_functions[p_index].create_function(error, server_create_functions[p_index].user_data); - if (server_create_functions[p_index].instance != nullptr) { - server_create_functions[p_index].instance->load_support_data(""); // Try loading default data. - } - } - return server_create_functions[p_index].instance; -} +Ref<TextServer> TextServerManager::find_interface(const String &p_name) const { + int idx = -1; + for (int i = 0; i < interfaces.size(); i++) { + if (interfaces[i]->get_name() == p_name) { + idx = i; + break; + }; + }; -TextServer *TextServerManager::_find_interface(const String &p_name) const { - for (int i = 0; i < server_create_count; i++) { - if (server_create_functions[i].name == p_name) { - return _get_interface(i); - } - } - return nullptr; + ERR_FAIL_COND_V(idx == -1, nullptr); + return interfaces[idx]; } -Array TextServerManager::_get_interfaces() const { +Array TextServerManager::get_interfaces() const { Array ret; - for (int i = 0; i < server_create_count; i++) { + for (int i = 0; i < interfaces.size(); i++) { Dictionary iface_info; iface_info["id"] = i; - iface_info["name"] = server_create_functions[i].name; + iface_info["name"] = interfaces[i]->get_name(); ret.push_back(iface_info); }; return ret; -}; - -bool TextServerManager::_set_primary_interface(int p_index) { - Error error; - TextServerManager::initialize(p_index, error); - return (error == OK); } -TextServer *TextServerManager::_get_primary_interface() const { - return server; +void TextServerManager::set_primary_interface(const Ref<TextServer> &p_primary_interface) { + if (p_primary_interface.is_null()) { + print_verbose("TextServer: Clearing primary interface"); + primary_interface.unref(); + } else { + primary_interface = p_primary_interface; + print_verbose("TextServer: Primary interface set to: \"" + primary_interface->get_name() + "\"."); + + if (OS::get_singleton()->get_main_loop()) { + OS::get_singleton()->get_main_loop()->notification(MainLoop::NOTIFICATION_TEXT_SERVER_CHANGED); + } + } } TextServerManager::TextServerManager() { @@ -155,29 +137,29 @@ TextServerManager::TextServerManager() { } TextServerManager::~TextServerManager() { - singleton = nullptr; - for (int i = 0; i < server_create_count; i++) { - if (server_create_functions[i].instance != nullptr) { - memdelete(server_create_functions[i].instance); - server_create_functions[i].instance = nullptr; - } + if (primary_interface.is_valid()) { + primary_interface.unref(); + } + while (interfaces.size() > 0) { + interfaces.remove_at(0); } + singleton = nullptr; } /*************************************************************************/ -bool TextServer::Glyph::operator==(const Glyph &p_a) const { +bool Glyph::operator==(const Glyph &p_a) const { return (p_a.index == index) && (p_a.font_rid == font_rid) && (p_a.font_size == font_size) && (p_a.start == start); } -bool TextServer::Glyph::operator!=(const Glyph &p_a) const { +bool Glyph::operator!=(const Glyph &p_a) const { return (p_a.index != index) || (p_a.font_rid != font_rid) || (p_a.font_size != font_size) || (p_a.start != start); } -bool TextServer::Glyph::operator<(const Glyph &p_a) const { +bool Glyph::operator<(const Glyph &p_a) const { if (p_a.start == start) { if (p_a.count == count) { - if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + if ((p_a.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) { return true; } else { return false; @@ -188,10 +170,10 @@ bool TextServer::Glyph::operator<(const Glyph &p_a) const { return p_a.start < start; } -bool TextServer::Glyph::operator>(const Glyph &p_a) const { +bool Glyph::operator>(const Glyph &p_a) const { if (p_a.start == start) { if (p_a.count == count) { - if ((p_a.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { + if ((p_a.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) { return false; } else { return true; @@ -205,8 +187,13 @@ bool TextServer::Glyph::operator>(const Glyph &p_a) const { void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("has_feature", "feature"), &TextServer::has_feature); ClassDB::bind_method(D_METHOD("get_name"), &TextServer::get_name); + ClassDB::bind_method(D_METHOD("get_features"), &TextServer::get_features); ClassDB::bind_method(D_METHOD("load_support_data", "filename"), &TextServer::load_support_data); + ClassDB::bind_method(D_METHOD("get_support_data_filename"), &TextServer::get_support_data_filename); + ClassDB::bind_method(D_METHOD("get_support_data_info"), &TextServer::get_support_data_info); + ClassDB::bind_method(D_METHOD("save_support_data", "filename"), &TextServer::save_support_data); + ClassDB::bind_method(D_METHOD("is_locale_right_to_left", "locale"), &TextServer::is_locale_right_to_left); ClassDB::bind_method(D_METHOD("name_to_tag", "name"), &TextServer::name_to_tag); @@ -219,7 +206,16 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("create_font"), &TextServer::create_font); - ClassDB::bind_method(D_METHOD("font_set_data", "data"), &TextServer::font_set_data); + ClassDB::bind_method(D_METHOD("font_set_data", "font_rid", "data"), &TextServer::font_set_data); + + ClassDB::bind_method(D_METHOD("font_set_style", "font_rid", "style"), &TextServer::font_set_style); + ClassDB::bind_method(D_METHOD("font_get_style", "font_rid"), &TextServer::font_get_style); + + ClassDB::bind_method(D_METHOD("font_set_name", "font_rid", "name"), &TextServer::font_set_name); + ClassDB::bind_method(D_METHOD("font_get_name", "font_rid"), &TextServer::font_get_name); + + ClassDB::bind_method(D_METHOD("font_set_style_name", "font_rid", "name"), &TextServer::font_set_style_name); + ClassDB::bind_method(D_METHOD("font_get_style_name", "font_rid"), &TextServer::font_get_style_name); ClassDB::bind_method(D_METHOD("font_set_antialiased", "font_rid", "antialiased"), &TextServer::font_set_antialiased); ClassDB::bind_method(D_METHOD("font_is_antialiased", "font_rid"), &TextServer::font_is_antialiased); @@ -299,7 +295,7 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_get_glyph_texture_idx", "font_rid", "size", "glyph"), &TextServer::font_get_glyph_texture_idx); ClassDB::bind_method(D_METHOD("font_set_glyph_texture_idx", "font_rid", "size", "glyph", "texture_idx"), &TextServer::font_set_glyph_texture_idx); - ClassDB::bind_method(D_METHOD("font_get_glyph_contours", "font", "size", "index"), &TextServer::_font_get_glyph_contours); + ClassDB::bind_method(D_METHOD("font_get_glyph_contours", "font", "size", "index"), &TextServer::font_get_glyph_contours); ClassDB::bind_method(D_METHOD("font_get_kerning_list", "font_rid", "size"), &TextServer::font_get_kerning_list); ClassDB::bind_method(D_METHOD("font_clear_kerning_map", "font_rid", "size"), &TextServer::font_clear_kerning_map); @@ -349,7 +345,10 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_set_direction", "shaped", "direction"), &TextServer::shaped_text_set_direction, DEFVAL(DIRECTION_AUTO)); ClassDB::bind_method(D_METHOD("shaped_text_get_direction", "shaped"), &TextServer::shaped_text_get_direction); - ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override", "shaped", "override"), &TextServer::_shaped_text_set_bidi_override); + ClassDB::bind_method(D_METHOD("shaped_text_set_bidi_override", "shaped", "override"), &TextServer::shaped_text_set_bidi_override); + + ClassDB::bind_method(D_METHOD("shaped_text_set_custom_punctuation", "shaped", "punct"), &TextServer::shaped_text_set_custom_punctuation); + ClassDB::bind_method(D_METHOD("shaped_text_get_custom_punctuation", "shaped"), &TextServer::shaped_text_get_custom_punctuation); ClassDB::bind_method(D_METHOD("shaped_text_set_orientation", "shaped", "orientation"), &TextServer::shaped_text_set_orientation, DEFVAL(ORIENTATION_HORIZONTAL)); ClassDB::bind_method(D_METHOD("shaped_text_get_orientation", "shaped"), &TextServer::shaped_text_get_orientation); @@ -372,12 +371,19 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_shape", "shaped"), &TextServer::shaped_text_shape); ClassDB::bind_method(D_METHOD("shaped_text_is_ready", "shaped"), &TextServer::shaped_text_is_ready); - ClassDB::bind_method(D_METHOD("shaped_text_get_glyphs", "shaped"), &TextServer::_shaped_text_get_glyphs); + ClassDB::bind_method(D_METHOD("shaped_text_get_glyphs", "shaped"), &TextServer::_shaped_text_get_glyphs_wrapper); + ClassDB::bind_method(D_METHOD("shaped_text_sort_logical", "shaped"), &TextServer::_shaped_text_sort_logical_wrapper); + ClassDB::bind_method(D_METHOD("shaped_text_get_glyph_count", "shaped"), &TextServer::shaped_text_get_glyph_count); ClassDB::bind_method(D_METHOD("shaped_text_get_range", "shaped"), &TextServer::shaped_text_get_range); - ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::_shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); - ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::_shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); - ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped"), &TextServer::_shaped_text_get_word_breaks); + ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks_adv", "shaped", "width", "start", "once", "break_flags"), &TextServer::shaped_text_get_line_breaks_adv, DEFVAL(0), DEFVAL(true), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); + ClassDB::bind_method(D_METHOD("shaped_text_get_line_breaks", "shaped", "width", "start", "break_flags"), &TextServer::shaped_text_get_line_breaks, DEFVAL(0), DEFVAL(BREAK_MANDATORY | BREAK_WORD_BOUND)); + ClassDB::bind_method(D_METHOD("shaped_text_get_word_breaks", "shaped", "grapheme_flags"), &TextServer::shaped_text_get_word_breaks); + + ClassDB::bind_method(D_METHOD("shaped_text_get_trim_pos", "shaped"), &TextServer::shaped_text_get_trim_pos); + ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_pos", "shaped"), &TextServer::shaped_text_get_ellipsis_pos); + ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_glyphs", "shaped"), &TextServer::_shaped_text_get_ellipsis_glyphs_wrapper); + ClassDB::bind_method(D_METHOD("shaped_text_get_ellipsis_glyph_count", "shaped"), &TextServer::shaped_text_get_ellipsis_glyph_count); ClassDB::bind_method(D_METHOD("shaped_text_overrun_trim_to_width", "shaped", "width", "overrun_trim_flags"), &TextServer::shaped_text_overrun_trim_to_width, DEFVAL(0), DEFVAL(OVERRUN_NO_TRIMMING)); @@ -391,24 +397,27 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_get_underline_position", "shaped"), &TextServer::shaped_text_get_underline_position); ClassDB::bind_method(D_METHOD("shaped_text_get_underline_thickness", "shaped"), &TextServer::shaped_text_get_underline_thickness); - ClassDB::bind_method(D_METHOD("shaped_text_get_carets", "shaped", "position"), &TextServer::_shaped_text_get_carets); - ClassDB::bind_method(D_METHOD("shaped_text_get_selection", "shaped", "start", "end"), &TextServer::_shaped_text_get_selection); + ClassDB::bind_method(D_METHOD("shaped_text_get_carets", "shaped", "position"), &TextServer::_shaped_text_get_carets_wrapper); + ClassDB::bind_method(D_METHOD("shaped_text_get_selection", "shaped", "start", "end"), &TextServer::shaped_text_get_selection); ClassDB::bind_method(D_METHOD("shaped_text_hit_test_grapheme", "shaped", "coords"), &TextServer::shaped_text_hit_test_grapheme); ClassDB::bind_method(D_METHOD("shaped_text_hit_test_position", "shaped", "coords"), &TextServer::shaped_text_hit_test_position); + ClassDB::bind_method(D_METHOD("shaped_text_get_grapheme_bounds", "shaped", "pos"), &TextServer::shaped_text_get_grapheme_bounds); ClassDB::bind_method(D_METHOD("shaped_text_next_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_next_grapheme_pos); ClassDB::bind_method(D_METHOD("shaped_text_prev_grapheme_pos", "shaped", "pos"), &TextServer::shaped_text_prev_grapheme_pos); ClassDB::bind_method(D_METHOD("shaped_text_draw", "shaped", "canvas", "pos", "clip_l", "clip_r", "color"), &TextServer::shaped_text_draw, DEFVAL(-1), DEFVAL(-1), DEFVAL(Color(1, 1, 1))); ClassDB::bind_method(D_METHOD("shaped_text_draw_outline", "shaped", "canvas", "pos", "clip_l", "clip_r", "outline_size", "color"), &TextServer::shaped_text_draw_outline, DEFVAL(-1), DEFVAL(-1), DEFVAL(1), DEFVAL(Color(1, 1, 1))); - ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direciton_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direciton_in_range); + ClassDB::bind_method(D_METHOD("shaped_text_get_dominant_direction_in_range", "shaped", "start", "end"), &TextServer::shaped_text_get_dominant_direction_in_range); ClassDB::bind_method(D_METHOD("format_number", "number", "language"), &TextServer::format_number, DEFVAL("")); ClassDB::bind_method(D_METHOD("parse_number", "number", "language"), &TextServer::parse_number, DEFVAL("")); ClassDB::bind_method(D_METHOD("percent_sign", "language"), &TextServer::percent_sign, DEFVAL("")); + ClassDB::bind_method(D_METHOD("strip_diacritics", "string"), &TextServer::strip_diacritics); + /* Direction */ BIND_ENUM_CONSTANT(DIRECTION_AUTO); BIND_ENUM_CONSTANT(DIRECTION_LTR); @@ -424,12 +433,14 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(JUSTIFICATION_WORD_BOUND); BIND_ENUM_CONSTANT(JUSTIFICATION_TRIM_EDGE_SPACES); BIND_ENUM_CONSTANT(JUSTIFICATION_AFTER_LAST_TAB); + BIND_ENUM_CONSTANT(JUSTIFICATION_CONSTRAIN_ELLIPSIS); /* LineBreakFlag */ BIND_ENUM_CONSTANT(BREAK_NONE); BIND_ENUM_CONSTANT(BREAK_MANDATORY); BIND_ENUM_CONSTANT(BREAK_WORD_BOUND); BIND_ENUM_CONSTANT(BREAK_GRAPHEME_BOUND); + BIND_ENUM_CONSTANT(BREAK_WORD_BOUND_ADAPTIVE); /* TextOverrunFlag */ BIND_ENUM_CONSTANT(OVERRUN_NO_TRIMMING); @@ -437,8 +448,10 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(OVERRUN_TRIM_WORD_ONLY); BIND_ENUM_CONSTANT(OVERRUN_ADD_ELLIPSIS); BIND_ENUM_CONSTANT(OVERRUN_ENFORCE_ELLIPSIS); + BIND_ENUM_CONSTANT(OVERRUN_JUSTIFICATION_AWARE); /* GraphemeFlag */ + BIND_ENUM_CONSTANT(GRAPHEME_IS_VALID); BIND_ENUM_CONSTANT(GRAPHEME_IS_RTL); BIND_ENUM_CONSTANT(GRAPHEME_IS_VIRTUAL); BIND_ENUM_CONSTANT(GRAPHEME_IS_SPACE); @@ -447,6 +460,8 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(GRAPHEME_IS_TAB); BIND_ENUM_CONSTANT(GRAPHEME_IS_ELONGATION); BIND_ENUM_CONSTANT(GRAPHEME_IS_PUNCTUATION); + BIND_ENUM_CONSTANT(GRAPHEME_IS_UNDERSCORE); + BIND_ENUM_CONSTANT(GRAPHEME_IS_CONNECTED); /* Hinting */ BIND_ENUM_CONSTANT(HINTING_NONE); @@ -468,114 +483,69 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CONIC); BIND_ENUM_CONSTANT(CONTOUR_CURVE_TAG_OFF_CUBIC); - /* Font Spacing*/ + /* Font Spacing */ BIND_ENUM_CONSTANT(SPACING_GLYPH); BIND_ENUM_CONSTANT(SPACING_SPACE); BIND_ENUM_CONSTANT(SPACING_TOP); BIND_ENUM_CONSTANT(SPACING_BOTTOM); -} -Vector3 TextServer::hex_code_box_font_size[2] = { Vector3(5, 5, 1), Vector3(10, 10, 2) }; -Ref<CanvasTexture> TextServer::hex_code_box_font_tex[2] = { nullptr, nullptr }; - -void TextServer::initialize_hex_code_box_fonts() { - static unsigned int tamsyn5x9_png_len = 175; - static unsigned char tamsyn5x9_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0x50, 0x00, 0x00, 0x00, 0x05, - 0x04, 0x03, 0x00, 0x00, 0x00, 0x20, 0x7c, 0x76, 0xda, 0x00, 0x00, 0x00, - 0x0f, 0x50, 0x4c, 0x54, 0x45, 0xfd, 0x07, 0x00, 0x00, 0x00, 0x00, 0x06, - 0x7e, 0x74, 0x00, 0x40, 0xc6, 0xff, 0xff, 0xff, 0x47, 0x9a, 0xd4, 0xc7, - 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, - 0x66, 0x00, 0x00, 0x00, 0x4e, 0x49, 0x44, 0x41, 0x54, 0x08, 0x1d, 0x05, - 0xc1, 0x21, 0x01, 0x00, 0x00, 0x00, 0x83, 0x30, 0x04, 0xc1, 0x10, 0xef, - 0x9f, 0xe9, 0x1b, 0x86, 0x2c, 0x17, 0xb9, 0xcc, 0x65, 0x0c, 0x73, 0x38, - 0xc7, 0xe6, 0x22, 0x19, 0x88, 0x98, 0x10, 0x48, 0x4a, 0x29, 0x85, 0x14, - 0x02, 0x89, 0x10, 0xa3, 0x1c, 0x0b, 0x31, 0xd6, 0xe6, 0x08, 0x69, 0x39, - 0x48, 0x44, 0xa0, 0x0d, 0x4a, 0x22, 0xa1, 0x94, 0x42, 0x0a, 0x01, 0x63, - 0x6d, 0x0e, 0x72, 0x18, 0x61, 0x8c, 0x74, 0x38, 0xc7, 0x26, 0x1c, 0xf3, - 0x71, 0x16, 0x15, 0x27, 0x6a, 0xc2, 0x2f, 0x00, 0x00, 0x00, 0x00, 0x49, - 0x45, 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 - }; + /* Font Style */ + BIND_ENUM_CONSTANT(FONT_BOLD); + BIND_ENUM_CONSTANT(FONT_ITALIC); + BIND_ENUM_CONSTANT(FONT_FIXED_WIDTH); +} - static unsigned int tamsyn10x20_png_len = 270; - static unsigned char tamsyn10x20_png[] = { - 0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a, 0x00, 0x00, 0x00, 0x0d, - 0x49, 0x48, 0x44, 0x52, 0x00, 0x00, 0x00, 0xa0, 0x00, 0x00, 0x00, 0x0a, - 0x04, 0x03, 0x00, 0x00, 0x00, 0xc1, 0x66, 0x48, 0x96, 0x00, 0x00, 0x00, - 0x0f, 0x50, 0x4c, 0x54, 0x45, 0x00, 0x00, 0x00, 0xf9, 0x07, 0x00, 0x5d, - 0x71, 0xa5, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x49, 0xdb, 0xcb, 0x7f, - 0x00, 0x00, 0x00, 0x01, 0x74, 0x52, 0x4e, 0x53, 0x00, 0x40, 0xe6, 0xd8, - 0x66, 0x00, 0x00, 0x00, 0xad, 0x49, 0x44, 0x41, 0x54, 0x28, 0xcf, 0xa5, - 0x92, 0x4b, 0x0e, 0x03, 0x31, 0x08, 0x43, 0xdf, 0x82, 0x83, 0x79, 0xe1, - 0xfb, 0x9f, 0xa9, 0x0b, 0x3e, 0x61, 0xa6, 0x1f, 0x55, 0xad, 0x14, 0x31, - 0x66, 0x42, 0x1c, 0x70, 0x0c, 0xb6, 0x00, 0x01, 0xb6, 0x08, 0xdb, 0x00, - 0x8d, 0xc2, 0x14, 0xb2, 0x55, 0xa1, 0xfe, 0x09, 0xc2, 0x26, 0xdc, 0x25, - 0x75, 0x22, 0x97, 0x1a, 0x25, 0x77, 0x28, 0x31, 0x02, 0x80, 0xc8, 0xdd, - 0x2c, 0x11, 0x1a, 0x54, 0x9f, 0xc8, 0xa2, 0x8a, 0x06, 0xa9, 0x93, 0x22, - 0xbd, 0xd4, 0xd0, 0x0c, 0xcf, 0x81, 0x2b, 0xca, 0xbb, 0x83, 0xe0, 0x10, - 0xe6, 0xad, 0xff, 0x10, 0x2a, 0x66, 0x34, 0x41, 0x58, 0x35, 0x54, 0x49, - 0x5a, 0x63, 0xa5, 0xc2, 0x87, 0xab, 0x52, 0x76, 0x9a, 0xba, 0xc6, 0xf4, - 0x75, 0x7a, 0x9e, 0x3c, 0x46, 0x86, 0x5c, 0xa3, 0xfd, 0x87, 0x0e, 0x75, - 0x08, 0x7b, 0xee, 0x7e, 0xea, 0x21, 0x5c, 0x4f, 0xf6, 0xc5, 0xc8, 0x4b, - 0xb9, 0x11, 0xf2, 0xd6, 0xe1, 0x8f, 0x84, 0x62, 0x7b, 0x67, 0xf9, 0x24, - 0xde, 0x6d, 0xbc, 0xb2, 0xcd, 0xb1, 0xf3, 0xf2, 0x2f, 0xe8, 0xe2, 0xe4, - 0xae, 0x4b, 0x4f, 0xcf, 0x2b, 0xdc, 0x8d, 0x0d, 0xf0, 0x00, 0x8f, 0x22, - 0x26, 0x65, 0x75, 0x8a, 0xe6, 0x84, 0x00, 0x00, 0x00, 0x00, 0x49, 0x45, - 0x4e, 0x44, 0xae, 0x42, 0x60, 0x82 - }; +Vector2 TextServer::get_hex_code_box_size(int p_size, char32_t p_index) const { + int w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)); + int sp = MAX(0, w - 1); + int sz = MAX(1, Math::round(p_size / 15.f)); - if (RenderingServer::get_singleton() != nullptr) { - Vector<uint8_t> hex_box_data; - - Ref<Image> image; - image.instantiate(); - - Ref<ImageTexture> hex_code_image_tex[2]; - - hex_box_data.resize(tamsyn5x9_png_len); - memcpy(hex_box_data.ptrw(), tamsyn5x9_png, tamsyn5x9_png_len); - image->load_png_from_buffer(hex_box_data); - hex_code_image_tex[0].instantiate(); - hex_code_image_tex[0]->create_from_image(image); - hex_code_box_font_tex[0].instantiate(); - hex_code_box_font_tex[0]->set_diffuse_texture(hex_code_image_tex[0]); - hex_code_box_font_tex[0]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); - hex_box_data.clear(); - - hex_box_data.resize(tamsyn10x20_png_len); - memcpy(hex_box_data.ptrw(), tamsyn10x20_png, tamsyn10x20_png_len); - image->load_png_from_buffer(hex_box_data); - hex_code_image_tex[1].instantiate(); - hex_code_image_tex[1]->create_from_image(image); - hex_code_box_font_tex[1].instantiate(); - hex_code_box_font_tex[1]->set_diffuse_texture(hex_code_image_tex[1]); - hex_code_box_font_tex[1]->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST); - hex_box_data.clear(); - } + return Vector2(4 + 3 * w + sp + 1, 15) * sz; } -void TextServer::finish_hex_code_box_fonts() { - if (hex_code_box_font_tex[0].is_valid()) { - hex_code_box_font_tex[0].unref(); +void TextServer::_draw_hex_code_box_number(RID p_canvas, int p_size, const Vector2 &p_pos, uint8_t p_index, const Color &p_color) const { + static uint8_t chars[] = { 0x7E, 0x30, 0x6D, 0x79, 0x33, 0x5B, 0x5F, 0x70, 0x7F, 0x7B, 0x77, 0x1F, 0x4E, 0x3D, 0x4F, 0x47, 0x00 }; + uint8_t x = chars[p_index]; + if (x & (1 << 6)) { + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos, Size2(3, 1) * p_size), p_color); + } + if (x & (1 << 5)) { + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(2, 0) * p_size, Size2(1, 3) * p_size), p_color); + } + if (x & (1 << 4)) { + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(2, 2) * p_size, Size2(1, 3) * p_size), p_color); + } + if (x & (1 << 3)) { + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(0, 4) * p_size, Size2(3, 1) * p_size), p_color); } - if (hex_code_box_font_tex[1].is_valid()) { - hex_code_box_font_tex[1].unref(); + if (x & (1 << 2)) { + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(0, 2) * p_size, Size2(1, 3) * p_size), p_color); + } + if (x & (1 << 1)) { + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos, Size2(1, 3) * p_size), p_color); + } + if (x & (1 << 0)) { + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(p_pos + Point2(0, 2) * p_size, Size2(3, 1) * p_size), p_color); } } -Vector2 TextServer::get_hex_code_box_size(int p_size, char32_t p_index) const { - int fnt = (p_size < 20) ? 0 : 1; +void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const { + if (p_index == 0) { + return; + } - real_t w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x; - real_t h = 2 * hex_code_box_font_size[fnt].y; - return Vector2(w + 4, h + 3 + 2 * hex_code_box_font_size[fnt].z); -} + int w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)); + int sp = MAX(0, w - 1); + int sz = MAX(1, Math::round(p_size / 15.f)); -void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const { - int fnt = (p_size < 20) ? 0 : 1; + Size2 size = Vector2(4 + 3 * w + sp, 15) * sz; + Point2 pos = p_pos - Point2i(0, size.y * 0.85); - ERR_FAIL_COND(hex_code_box_font_tex[fnt].is_null()); + // Draw frame. + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(sz, size.y)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(size.x - sz, 0), Size2(sz, size.y)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(size.x, sz)), p_color); + RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, size.y - sz), Size2(size.x, sz)), p_color); uint8_t a = p_index & 0x0F; uint8_t b = (p_index >> 4) & 0x0F; @@ -584,57 +554,31 @@ void TextServer::draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_po uint8_t e = (p_index >> 16) & 0x0F; uint8_t f = (p_index >> 20) & 0x0F; - Vector2 pos = p_pos; - Rect2 dest = Rect2(Vector2(), Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y)); - - real_t w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)) * hex_code_box_font_size[fnt].x; - real_t h = 2 * hex_code_box_font_size[fnt].y; - - pos.y -= Math::floor((h + 3 + hex_code_box_font_size[fnt].z) * 0.75); - - RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color); - RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(w + 2, 0), Size2(1, h + 2 + 2 * hex_code_box_font_size[fnt].z)), p_color); - RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, 0), Size2(w + 2, 1)), p_color); - RenderingServer::get_singleton()->canvas_item_add_rect(p_canvas, Rect2(pos + Point2(0, h + 2 + 2 * hex_code_box_font_size[fnt].z), Size2(w + 2, 1)), p_color); - - pos += Point2(2, 2); + // Draw hex code. if (p_index <= 0xFF) { - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 2) * sz, b, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 8) * sz, a, p_color); } else if (p_index <= 0xFFFF) { - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(d * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 0); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(c * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 1) + Point2(0, hex_code_box_font_size[fnt].z); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 2) * sz, d, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(6, 2) * sz, c, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 8) * sz, b, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(6, 8) * sz, a, p_color); } else { - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 0); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(f * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 0); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(e * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(2, 0); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(d * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(0, 1) + Point2(0, hex_code_box_font_size[fnt].z); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(c * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(1, 1) + Point2(0, hex_code_box_font_size[fnt].z); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(b * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); - dest.position = pos + Vector2(hex_code_box_font_size[fnt].x, hex_code_box_font_size[fnt].y) * Point2(2, 1) + Point2(0, hex_code_box_font_size[fnt].z); - RenderingServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas, dest, hex_code_box_font_tex[fnt]->get_rid(), Rect2(Point2(a * hex_code_box_font_size[fnt].x, 0), dest.size), p_color, false, false); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 2) * sz, f, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(6, 2) * sz, e, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(10, 2) * sz, d, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(2, 8) * sz, c, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(6, 8) * sz, b, p_color); + _draw_hex_code_box_number(p_canvas, sz, pos + Point2(10, 8) * sz, a, p_color); } } -Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<real_t> &p_width, int p_start, bool p_once, uint8_t /*TextBreakFlag*/ p_break_flags) const { - Vector<Vector2i> lines; +PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint16_t /*TextBreakFlag*/ p_break_flags) const { + PackedInt32Array lines; ERR_FAIL_COND_V(p_width.is_empty(), lines); const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped); - const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); const Vector2i &range = shaped_text_get_range(p_shaped); real_t width = 0.f; @@ -642,8 +586,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const int last_safe_break = -1; int chunk = 0; - int l_size = logical.size(); - const Glyph *l_gl = logical.ptr(); + int l_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); for (int i = 0; i < l_size; i++) { if (l_gl[i].start < p_start) { @@ -651,7 +595,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const } if (l_gl[i].count > 0) { if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) { - lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end)); + lines.push_back(line_start); + lines.push_back(l_gl[last_safe_break].end); line_start = l_gl[last_safe_break].end; i = last_safe_break; last_safe_break = -1; @@ -667,7 +612,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const } if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) { if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { - lines.push_back(Vector2i(line_start, l_gl[i].end)); + lines.push_back(line_start); + lines.push_back(l_gl[i].end); line_start = l_gl[i].end; last_safe_break = -1; width = 0; @@ -691,27 +637,31 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks_adv(RID p_shaped, const } if (l_size > 0) { - lines.push_back(Vector2i(line_start, range.y)); + if (lines.size() == 0 || lines[lines.size() - 1] < range.y) { + lines.push_back(line_start); + lines.push_back(range.y); + } } else { - lines.push_back(Vector2i(0, 0)); + lines.push_back(0); + lines.push_back(0); } return lines; } -Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint8_t /*TextBreakFlag*/ p_break_flags) const { - Vector<Vector2i> lines; +PackedInt32Array TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint16_t /*TextBreakFlag*/ p_break_flags) const { + PackedInt32Array lines; const_cast<TextServer *>(this)->shaped_text_update_breaks(p_shaped); - const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); const Vector2i &range = shaped_text_get_range(p_shaped); real_t width = 0.f; int line_start = MAX(p_start, range.x); int last_safe_break = -1; int word_count = 0; - int l_size = logical.size(); - const Glyph *l_gl = logical.ptr(); + + int l_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); for (int i = 0; i < l_size; i++) { if (l_gl[i].start < p_start) { @@ -719,7 +669,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_ } if (l_gl[i].count > 0) { if ((p_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > p_width) && (last_safe_break >= 0)) { - lines.push_back(Vector2i(line_start, l_gl[last_safe_break].end)); + lines.push_back(line_start); + lines.push_back(l_gl[last_safe_break].end); line_start = l_gl[last_safe_break].end; i = last_safe_break; last_safe_break = -1; @@ -729,7 +680,8 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_ } if ((p_break_flags & BREAK_MANDATORY) == BREAK_MANDATORY) { if ((l_gl[i].flags & GRAPHEME_IS_BREAK_HARD) == GRAPHEME_IS_BREAK_HARD) { - lines.push_back(Vector2i(line_start, l_gl[i].end)); + lines.push_back(line_start); + lines.push_back(l_gl[i].end); line_start = l_gl[i].end; last_safe_break = -1; width = 0; @@ -753,51 +705,49 @@ Vector<Vector2i> TextServer::shaped_text_get_line_breaks(RID p_shaped, real_t p_ } if (l_size > 0) { - if (lines.size() == 0 || lines[lines.size() - 1].y < range.y) { - lines.push_back(Vector2i(line_start, range.y)); + if (lines.size() == 0 || lines[lines.size() - 1] < range.y) { + lines.push_back(line_start); + lines.push_back(range.y); } } else { - lines.push_back(Vector2i(0, 0)); + lines.push_back(0); + lines.push_back(0); } return lines; } -Vector<Vector2i> TextServer::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const { - Vector<Vector2i> words; +PackedInt32Array TextServer::shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags) const { + PackedInt32Array words; const_cast<TextServer *>(this)->shaped_text_update_justification_ops(p_shaped); - const Vector<Glyph> &logical = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); const Vector2i &range = shaped_text_get_range(p_shaped); int word_start = range.x; - int l_size = logical.size(); - const Glyph *l_gl = logical.ptr(); + int l_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); for (int i = 0; i < l_size; i++) { if (l_gl[i].count > 0) { if ((l_gl[i].flags & p_grapheme_flags) != 0) { - words.push_back(Vector2i(word_start, l_gl[i].start)); + words.push_back(word_start); + words.push_back(l_gl[i].start); word_start = l_gl[i].end; } } } if (l_size > 0) { - words.push_back(Vector2i(word_start, range.y)); + words.push_back(word_start); + words.push_back(range.y); } return words; } -TextServer::TrimData TextServer::shaped_text_get_trim_data(RID p_shaped) const { - WARN_PRINT("Getting overrun data not supported by this TextServer."); - return TrimData(); -} - -void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const { +CaretInfo TextServer::shaped_text_get_carets(RID p_shaped, int p_position) const { Vector<Rect2> carets; - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); + TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); const Vector2 &range = shaped_text_get_range(p_shaped); real_t ascent = shaped_text_get_ascent(p_shaped); @@ -805,11 +755,12 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l real_t height = (ascent + descent) / 2; real_t off = 0.0f; - p_leading_dir = DIRECTION_AUTO; - p_trailing_dir = DIRECTION_AUTO; + CaretInfo caret; + caret.l_dir = DIRECTION_AUTO; + caret.t_dir = DIRECTION_AUTO; - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); for (int i = 0; i < v_size; i++) { if (glyphs[i].count > 0) { @@ -825,13 +776,13 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l cr.position.y = -ascent; cr.position.x = off; if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { - p_trailing_dir = DIRECTION_RTL; + caret.t_dir = DIRECTION_RTL; for (int j = 0; j < glyphs[i].count; j++) { cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat; cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat; } } else { - p_trailing_dir = DIRECTION_LTR; + caret.t_dir = DIRECTION_LTR; for (int j = 0; j < glyphs[i].count; j++) { cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat; } @@ -845,19 +796,19 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l cr.position.x = -ascent; cr.position.y = off; if ((glyphs[i].flags & GRAPHEME_IS_RTL) == GRAPHEME_IS_RTL) { - p_trailing_dir = DIRECTION_RTL; + caret.t_dir = DIRECTION_RTL; for (int j = 0; j < glyphs[i].count; j++) { cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat; cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat; } } else { - p_trailing_dir = DIRECTION_LTR; + caret.t_dir = DIRECTION_LTR; for (int j = 0; j < glyphs[i].count; j++) { cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat; } } } - p_trailing_caret = cr; + caret.t_caret = cr; } // Caret after grapheme (bottom / right). if (p_position == glyphs[i].end && ((glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL)) { @@ -872,13 +823,13 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l } cr.position.x = off; if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) { - p_leading_dir = DIRECTION_LTR; + caret.l_dir = DIRECTION_LTR; for (int j = 0; j < glyphs[i].count; j++) { cr.position.x += glyphs[i + j].advance * glyphs[i + j].repeat; cr.size.x -= glyphs[i + j].advance * glyphs[i + j].repeat; } } else { - p_leading_dir = DIRECTION_RTL; + caret.l_dir = DIRECTION_RTL; for (int j = 0; j < glyphs[i].count; j++) { cr.size.x += glyphs[i + j].advance * glyphs[i + j].repeat; } @@ -894,19 +845,19 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l } cr.position.y = off; if ((glyphs[i].flags & GRAPHEME_IS_RTL) != GRAPHEME_IS_RTL) { - p_leading_dir = DIRECTION_LTR; + caret.l_dir = DIRECTION_LTR; for (int j = 0; j < glyphs[i].count; j++) { cr.position.y += glyphs[i + j].advance * glyphs[i + j].repeat; cr.size.y -= glyphs[i + j].advance * glyphs[i + j].repeat; } } else { - p_leading_dir = DIRECTION_RTL; + caret.l_dir = DIRECTION_RTL; for (int j = 0; j < glyphs[i].count; j++) { cr.size.y += glyphs[i + j].advance * glyphs[i + j].repeat; } } } - p_leading_caret = cr; + caret.l_caret = cr; } // Caret inside grapheme (middle). if (p_position > glyphs[i].start && p_position < glyphs[i].end && (glyphs[i].flags & GRAPHEME_IS_VIRTUAL) != GRAPHEME_IS_VIRTUAL) { @@ -935,17 +886,29 @@ void TextServer::shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_l cr.position.y = off + char_adv * (p_position - glyphs[i].start); } } - p_trailing_caret = cr; - p_leading_caret = cr; + caret.t_caret = cr; + caret.l_caret = cr; } } off += glyphs[i].advance * glyphs[i].repeat; } + return caret; } -TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const { - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); +Dictionary TextServer::_shaped_text_get_carets_wrapper(RID p_shaped, int p_position) const { + Dictionary ret; + + CaretInfo caret = shaped_text_get_carets(p_shaped, p_position); + + ret["leading_rect"] = caret.l_caret; + ret["leading_direction"] = caret.l_dir; + ret["trailing_rect"] = caret.t_caret; + ret["trailing_direction"] = caret.t_dir; + + return ret; +} +TextServer::Direction TextServer::shaped_text_get_dominant_direction_in_range(RID p_shaped, int p_start, int p_end) const { if (p_start == p_end) { return DIRECTION_AUTO; } @@ -956,8 +919,8 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI int rtl = 0; int ltr = 0; - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); for (int i = 0; i < v_size; i++) { if ((glyphs[i].end > start) && (glyphs[i].start < end)) { @@ -981,7 +944,6 @@ TextServer::Direction TextServer::shaped_text_get_dominant_direciton_in_range(RI Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const { Vector<Vector2> ranges; - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); if (p_start == p_end) { return ranges; @@ -990,8 +952,8 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, int start = MIN(p_start, p_end); int end = MAX(p_start, p_end); - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); real_t off = 0.0f; for (int i = 0; i < v_size; i++) { @@ -1062,7 +1024,7 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, while (j < ranges.size()) { if (Math::is_equal_approx(ranges[i].y, ranges[j].x, (real_t)UNIT_EPSILON)) { ranges.write[i].y = ranges[j].y; - ranges.remove(j); + ranges.remove_at(j); continue; } j++; @@ -1074,13 +1036,11 @@ Vector<Vector2> TextServer::shaped_text_get_selection(RID p_shaped, int p_start, } int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, real_t p_coords) const { - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); - // Exact grapheme hit test, return -1 if missed. real_t off = 0.0f; - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); for (int i = 0; i < v_size; i++) { for (int j = 0; j < glyphs[i].repeat; j++) { @@ -1094,10 +1054,8 @@ int TextServer::shaped_text_hit_test_grapheme(RID p_shaped, real_t p_coords) con } int TextServer::shaped_text_hit_test_position(RID p_shaped, real_t p_coords) const { - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); - - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); // Cursor placement hit test. @@ -1163,10 +1121,30 @@ int TextServer::shaped_text_hit_test_position(RID p_shaped, real_t p_coords) con return 0; } -int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) { - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); +Vector2 TextServer::shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const { + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); + + real_t off = 0.0f; + for (int i = 0; i < v_size; i++) { + if ((glyphs[i].count > 0) && ((glyphs[i].index != 0) || ((glyphs[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE))) { + if (glyphs[i].start <= p_pos && glyphs[i].end >= p_pos) { + real_t advance = 0.f; + for (int j = 0; j < glyphs[i].count; j++) { + advance += glyphs[i + j].advance; + } + return Vector2(off, off + advance); + } + } + off += glyphs[i].advance * glyphs[i].repeat; + } + + return Vector2(); +} + +int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const { + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); for (int i = 0; i < v_size; i++) { if (p_pos >= glyphs[i].start && p_pos < glyphs[i].end) { return glyphs[i].end; @@ -1175,10 +1153,9 @@ int TextServer::shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) { return p_pos; } -int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) { - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); +int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const { + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); for (int i = 0; i < v_size; i++) { if (p_pos > glyphs[i].start && p_pos <= glyphs[i].end) { return glyphs[i].start; @@ -1189,26 +1166,30 @@ int TextServer::shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) { } void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, real_t p_clip_l, real_t p_clip_r, const Color &p_color) const { - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); bool hex_codes = shaped_text_get_preserve_control(p_shaped) || shaped_text_get_preserve_invalid(p_shaped); bool rtl = shaped_text_get_direction(p_shaped) == DIRECTION_RTL; - TrimData trim_data = shaped_text_get_trim_data(p_shaped); - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); + int ellipsis_pos = shaped_text_get_ellipsis_pos(p_shaped); + int trim_pos = shaped_text_get_trim_pos(p_shaped); + + const Glyph *ellipsis_glyphs = shaped_text_get_ellipsis_glyphs(p_shaped); + int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped); + + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); Vector2 ofs = p_pos; // Draw RTL ellipsis string when needed. - if (rtl && trim_data.ellipsis_pos >= 0) { - for (int i = trim_data.ellipsis_glyph_buf.size() - 1; i >= 0; i--) { - for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) { - font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color); + if (rtl && ellipsis_pos >= 0) { + for (int i = ellipsis_gl_size - 1; i >= 0; i--) { + for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) { + font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color); if (orientation == ORIENTATION_HORIZONTAL) { - ofs.x += trim_data.ellipsis_glyph_buf[i].advance; + ofs.x += ellipsis_glyphs[i].advance; } else { - ofs.y += trim_data.ellipsis_glyph_buf[i].advance; + ofs.y += ellipsis_glyphs[i].advance; } } } @@ -1242,13 +1223,13 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p } } } - if (trim_data.trim_pos >= 0) { + if (trim_pos >= 0) { if (rtl) { - if (i < trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { + if (i < trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { continue; } } else { - if (i >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { + if (i >= trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { break; } } @@ -1267,14 +1248,14 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p } } // Draw LTR ellipsis string when needed. - if (!rtl && trim_data.ellipsis_pos >= 0) { - for (int i = 0; i < trim_data.ellipsis_glyph_buf.size(); i++) { - for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) { - font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color); + if (!rtl && ellipsis_pos >= 0) { + for (int i = 0; i < ellipsis_gl_size; i++) { + for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) { + font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color); if (orientation == ORIENTATION_HORIZONTAL) { - ofs.x += trim_data.ellipsis_glyph_buf[i].advance; + ofs.x += ellipsis_glyphs[i].advance; } else { - ofs.y += trim_data.ellipsis_glyph_buf[i].advance; + ofs.y += ellipsis_glyphs[i].advance; } } } @@ -1282,24 +1263,28 @@ void TextServer::shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_p } void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, real_t p_clip_l, real_t p_clip_r, int p_outline_size, const Color &p_color) const { - const Vector<TextServer::Glyph> visual = shaped_text_get_glyphs(p_shaped); TextServer::Orientation orientation = shaped_text_get_orientation(p_shaped); bool rtl = (shaped_text_get_direction(p_shaped) == DIRECTION_RTL); - TrimData trim_data = shaped_text_get_trim_data(p_shaped); - int v_size = visual.size(); - const Glyph *glyphs = visual.ptr(); + int ellipsis_pos = shaped_text_get_ellipsis_pos(p_shaped); + int trim_pos = shaped_text_get_trim_pos(p_shaped); + + const Glyph *ellipsis_glyphs = shaped_text_get_ellipsis_glyphs(p_shaped); + int ellipsis_gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped); + + int v_size = shaped_text_get_glyph_count(p_shaped); + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); Vector2 ofs = p_pos; // Draw RTL ellipsis string when needed. - if (rtl && trim_data.ellipsis_pos >= 0) { - for (int i = trim_data.ellipsis_glyph_buf.size() - 1; i >= 0; i--) { - for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) { - font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color); + if (rtl && ellipsis_pos >= 0) { + for (int i = ellipsis_gl_size - 1; i >= 0; i--) { + for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) { + font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color); if (orientation == ORIENTATION_HORIZONTAL) { - ofs.x += trim_data.ellipsis_glyph_buf[i].advance; + ofs.x += ellipsis_glyphs[i].advance; } else { - ofs.y += trim_data.ellipsis_glyph_buf[i].advance; + ofs.y += ellipsis_glyphs[i].advance; } } } @@ -1333,13 +1318,13 @@ void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vect } } } - if (trim_data.trim_pos >= 0) { + if (trim_pos >= 0) { if (rtl) { - if (i < trim_data.trim_pos) { + if (i < trim_pos) { continue; } } else { - if (i >= trim_data.trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { + if (i >= trim_pos && (glyphs[j].flags & TextServer::GRAPHEME_IS_VIRTUAL) != TextServer::GRAPHEME_IS_VIRTUAL) { break; } } @@ -1355,48 +1340,154 @@ void TextServer::shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vect } } // Draw LTR ellipsis string when needed. - if (!rtl && trim_data.ellipsis_pos >= 0) { - for (int i = 0; i < trim_data.ellipsis_glyph_buf.size(); i++) { - for (int j = 0; j < trim_data.ellipsis_glyph_buf[i].repeat; j++) { - font_draw_glyph(trim_data.ellipsis_glyph_buf[i].font_rid, p_canvas, trim_data.ellipsis_glyph_buf[i].font_size, ofs + Vector2(trim_data.ellipsis_glyph_buf[i].x_off, trim_data.ellipsis_glyph_buf[i].y_off), trim_data.ellipsis_glyph_buf[i].index, p_color); + if (!rtl && ellipsis_pos >= 0) { + for (int i = 0; i < ellipsis_gl_size; i++) { + for (int j = 0; j < ellipsis_glyphs[i].repeat; j++) { + font_draw_glyph(ellipsis_glyphs[i].font_rid, p_canvas, ellipsis_glyphs[i].font_size, ofs + Vector2(ellipsis_glyphs[i].x_off, ellipsis_glyphs[i].y_off), ellipsis_glyphs[i].index, p_color); if (orientation == ORIENTATION_HORIZONTAL) { - ofs.x += trim_data.ellipsis_glyph_buf[i].advance; + ofs.x += ellipsis_glyphs[i].advance; } else { - ofs.y += trim_data.ellipsis_glyph_buf[i].advance; + ofs.y += ellipsis_glyphs[i].advance; } } } } } -Dictionary TextServer::_font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const { - Vector<Vector3> points; - Vector<int32_t> contours; - bool orientation; - bool ok = font_get_glyph_contours(p_font, p_size, p_index, points, contours, orientation); - Dictionary out; - - if (ok) { - out["points"] = points; - out["contours"] = contours; - out["orientation"] = orientation; +void TextServer::_diacritics_map_add(const String &p_from, char32_t p_to) { + for (int i = 0; i < p_from.size(); i++) { + diacritics_map[p_from[i]] = p_to; } - return out; } -void TextServer::_shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) { - Vector<Vector2i> overrides; - for (int i = 0; i < p_override.size(); i++) { - overrides.push_back(p_override[i]); +void TextServer::_init_diacritics_map() { + diacritics_map.clear(); + + // Latin. + _diacritics_map_add(U"ÀÁÂÃÄÅĀĂĄǍǞǠǺȀȂȦḀẠẢẤẦẨẪẬẮẰẲẴẶ", U'A'); + _diacritics_map_add(U"àáâãäåāăąǎǟǡǻȁȃȧḁẚạảấầẩẫậắằẳẵặ", U'a'); + _diacritics_map_add(U"ǢǼ", U'Æ'); + _diacritics_map_add(U"ǣǽ", U'æ'); + _diacritics_map_add(U"ḂḄḆ", U'B'); + _diacritics_map_add(U"ḃḅḇ", U'b'); + _diacritics_map_add(U"ÇĆĈĊČḈ", U'C'); + _diacritics_map_add(U"çćĉċčḉ", U'c'); + _diacritics_map_add(U"ĎḊḌḎḐḒ", U'D'); + _diacritics_map_add(U"ďḋḍḏḑḓ", U'd'); + _diacritics_map_add(U"ÈÉÊËĒĔĖĘĚȆȨḔḖḘḚḜẸẺẼẾỀỂỄỆ", U'E'); + _diacritics_map_add(U"èéêëēĕėęěȇȩḕḗḙḛḝẹẻẽếềểễệ", U'e'); + _diacritics_map_add(U"Ḟ", U'F'); + _diacritics_map_add(U"ḟ", U'f'); + _diacritics_map_add(U"ĜĞĠĢǦǴḠ", U'G'); + _diacritics_map_add(U"ĝğġģǧǵḡ", U'g'); + _diacritics_map_add(U"ĤȞḢḤḦḨḪ", U'H'); + _diacritics_map_add(U"ĥȟḣḥḧḩḫẖ", U'h'); + _diacritics_map_add(U"ÌÍÎÏĨĪĬĮİǏȈȊḬḮỈỊ", U'I'); + _diacritics_map_add(U"ìíîïĩīĭįıǐȉȋḭḯỉị", U'i'); + _diacritics_map_add(U"Ĵ", U'J'); + _diacritics_map_add(U"ĵ", U'j'); + _diacritics_map_add(U"ĶǨḰḲḴ", U'K'); + _diacritics_map_add(U"ķĸǩḱḳḵ", U'k'); + _diacritics_map_add(U"ĹĻĽĿḶḸḺḼ", U'L'); + _diacritics_map_add(U"ĺļľŀḷḹḻḽ", U'l'); + _diacritics_map_add(U"ḾṀṂ", U'M'); + _diacritics_map_add(U"ḿṁṃ", U'm'); + _diacritics_map_add(U"ÑŃŅŇǸṄṆṈṊ", U'N'); + _diacritics_map_add(U"ñńņňʼnǹṅṇṉṋ", U'n'); + _diacritics_map_add(U"ÒÓÔÕÖŌŎŐƠǑǪǬȌȎȪȬȮȰṌṎṐṒỌỎỐỒỔỖỘỚỜỞỠỢ", U'O'); + _diacritics_map_add(U"òóôõöōŏőơǒǫǭȍȏȫȭȯȱṍṏṑṓọỏốồổỗộớờởỡợ", U'o'); + _diacritics_map_add(U"ṔṖ", U'P'); + _diacritics_map_add(U"ṗṕ", U'p'); + _diacritics_map_add(U"ŔŖŘȐȒṘṚṜṞ", U'R'); + _diacritics_map_add(U"ŕŗřȑȓṙṛṝṟ", U'r'); + _diacritics_map_add(U"ŚŜŞŠȘṠṢṤṦṨ", U'S'); + _diacritics_map_add(U"śŝşšſșṡṣṥṧṩẛẜẝ", U's'); + _diacritics_map_add(U"ŢŤȚṪṬṮṰ", U'T'); + _diacritics_map_add(U"ţťțṫṭṯṱẗ", U't'); + _diacritics_map_add(U"ÙÚÛÜŨŪŬŮŰŲƯǓǕǗǙǛȔȖṲṴṶṸṺỤỦỨỪỬỮỰ", U'U'); + _diacritics_map_add(U"ùúûüũūŭůűųưǔǖǘǚǜȕȗṳṵṷṹṻụủứừửữự", U'u'); + _diacritics_map_add(U"ṼṾ", U'V'); + _diacritics_map_add(U"ṽṿ", U'v'); + _diacritics_map_add(U"ŴẀẂẄẆẈ", U'W'); + _diacritics_map_add(U"ŵẁẃẅẇẉẘ", U'w'); + _diacritics_map_add(U"ẊẌ", U'X'); + _diacritics_map_add(U"ẋẍ", U'x'); + _diacritics_map_add(U"ÝŶẎỲỴỶỸỾ", U'Y'); + _diacritics_map_add(U"ýÿŷẏẙỳỵỷỹỿ", U'y'); + _diacritics_map_add(U"ŹŻŽẐẒẔ", U'Z'); + _diacritics_map_add(U"źżžẑẓẕ", U'z'); + + // Greek. + _diacritics_map_add(U"ΆἈἉἊἋἌἍἎἏᾈᾉᾊᾋᾌᾍᾎᾏᾸᾹᾺΆᾼ", U'Α'); + _diacritics_map_add(U"άἀἁἂἃἄἅἆἇὰάᾀᾁᾂᾃᾄᾅᾆᾇᾰᾱᾲᾳᾴᾶᾷ", U'α'); + _diacritics_map_add(U"ΈἘἙἚἛἜἝῈΈ", U'Ε'); + _diacritics_map_add(U"έἐἑἒἓἔἕὲέ", U'ε'); + _diacritics_map_add(U"ΉἨἩἪἫἬἭἮἯᾘᾙᾚᾛᾜᾝᾞᾟῊΉῌ", U'Η'); + _diacritics_map_add(U"ήἠἡἢἣἤἥἦἧὴήᾐᾑᾒᾓᾔᾕᾖᾗῂῃῄῆῇ", U'η'); + _diacritics_map_add(U"ΊΪἸἹἺἻἼἽἾἿῘῙῚΊ", U'Ι'); + _diacritics_map_add(U"ίΐϊἰἱἲἳἴἵἶἷὶίῐῑῒΐῖῗ", U'ι'); + _diacritics_map_add(U"ΌὈὉὊὋὌὍῸΌ", U'Ο'); + _diacritics_map_add(U"όὀὁὂὃὄὅὸό", U'ο'); + _diacritics_map_add(U"Ῥ", U'Ρ'); + _diacritics_map_add(U"ῤῥ", U'ρ'); + _diacritics_map_add(U"ΎΫϓϔὙὛὝὟῨῩῪΎ", U'Υ'); + _diacritics_map_add(U"ΰϋύὐὑὒὓὔὕὖὗὺύῠῡῢΰῦῧ", U'υ'); + _diacritics_map_add(U"ΏὨὩὪὫὬὭὮὯᾨᾩᾪᾫᾬᾭᾮᾯῺΏῼ", U'Ω'); + _diacritics_map_add(U"ώὠὡὢὣὤὥὦὧὼώᾠᾡᾢᾣᾤᾥᾦᾧῲῳῴῶῷ", U'ω'); + + // Cyrillic. + _diacritics_map_add(U"ӐӒ", U'А'); + _diacritics_map_add(U"ӑӓ", U'а'); + _diacritics_map_add(U"ЀЁӖ", U'Е'); + _diacritics_map_add(U"ѐёӗ", U'е'); + _diacritics_map_add(U"Ӛ", U'Ә'); + _diacritics_map_add(U"ӛ", U'ә'); + _diacritics_map_add(U"Ӝ", U'Ж'); + _diacritics_map_add(U"ӝ", U'ж'); + _diacritics_map_add(U"Ӟ", U'З'); + _diacritics_map_add(U"ӟ", U'з'); + _diacritics_map_add(U"Ѓ", U'Г'); + _diacritics_map_add(U"ѓ", U'г'); + _diacritics_map_add(U"Ї", U'І'); + _diacritics_map_add(U"ї", U'і'); + _diacritics_map_add(U"ЍӢӤЙ", U'И'); + _diacritics_map_add(U"ѝӣӥй", U'и'); + _diacritics_map_add(U"Ќ", U'К'); + _diacritics_map_add(U"ќ", U'к'); + _diacritics_map_add(U"Ӧ", U'О'); + _diacritics_map_add(U"ӧ", U'о'); + _diacritics_map_add(U"Ӫ", U'Ө'); + _diacritics_map_add(U"ӫ", U'ө'); + _diacritics_map_add(U"Ӭ", U'Э'); + _diacritics_map_add(U"ӭ", U'э'); + _diacritics_map_add(U"ЎӮӰӲ", U'У'); + _diacritics_map_add(U"ўӯӱӳ", U'у'); + _diacritics_map_add(U"Ӵ", U'Ч'); + _diacritics_map_add(U"ӵ", U'ч'); + _diacritics_map_add(U"Ӹ", U'Ы'); + _diacritics_map_add(U"ӹ", U'ы'); +} + +String TextServer::strip_diacritics(const String &p_string) const { + String result; + for (int i = 0; i < p_string.length(); i++) { + if (p_string[i] < 0x02B0 || p_string[i] > 0x036F) { // Skip combining diacritics. + if (diacritics_map.has(p_string[i])) { + result += diacritics_map[p_string[i]]; + } else { + result += p_string[i]; + } + } } - shaped_text_set_bidi_override(p_shaped, overrides); + return result; } -Array TextServer::_shaped_text_get_glyphs(RID p_shaped) const { +Array TextServer::_shaped_text_get_glyphs_wrapper(RID p_shaped) const { Array ret; - Vector<Glyph> glyphs = shaped_text_get_glyphs(p_shaped); - for (int i = 0; i < glyphs.size(); i++) { + const Glyph *glyphs = shaped_text_get_glyphs(p_shaped); + int gl_size = shaped_text_get_glyph_count(p_shaped); + for (int i = 0; i < gl_size; i++) { Dictionary glyph; glyph["start"] = glyphs[i].start; @@ -1416,66 +1507,58 @@ Array TextServer::_shaped_text_get_glyphs(RID p_shaped) const { return ret; } -Array TextServer::_shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const { +Array TextServer::_shaped_text_sort_logical_wrapper(RID p_shaped) { Array ret; - Vector<Vector2i> lines = shaped_text_get_line_breaks_adv(p_shaped, p_width, p_start, p_once, p_break_flags); - for (int i = 0; i < lines.size(); i++) { - ret.push_back(lines[i]); - } - - return ret; -} + const Glyph *glyphs = shaped_text_sort_logical(p_shaped); + int gl_size = shaped_text_get_glyph_count(p_shaped); + for (int i = 0; i < gl_size; i++) { + Dictionary glyph; -Array TextServer::_shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint8_t p_break_flags) const { - Array ret; + glyph["start"] = glyphs[i].start; + glyph["end"] = glyphs[i].end; + glyph["repeat"] = glyphs[i].repeat; + glyph["count"] = glyphs[i].count; + glyph["flags"] = glyphs[i].flags; + glyph["offset"] = Vector2(glyphs[i].x_off, glyphs[i].y_off); + glyph["advance"] = glyphs[i].advance; + glyph["font_rid"] = glyphs[i].font_rid; + glyph["font_size"] = glyphs[i].font_size; + glyph["index"] = glyphs[i].index; - Vector<Vector2i> lines = shaped_text_get_line_breaks(p_shaped, p_width, p_start, p_break_flags); - for (int i = 0; i < lines.size(); i++) { - ret.push_back(lines[i]); + ret.push_back(glyph); } return ret; } -Array TextServer::_shaped_text_get_word_breaks(RID p_shaped) const { +Array TextServer::_shaped_text_get_ellipsis_glyphs_wrapper(RID p_shaped) const { Array ret; - Vector<Vector2i> words = shaped_text_get_word_breaks(p_shaped); - for (int i = 0; i < words.size(); i++) { - ret.push_back(words[i]); - } - - return ret; -} - -Dictionary TextServer::_shaped_text_get_carets(RID p_shaped, int p_position) const { - Dictionary ret; - - Rect2 l_caret, t_caret; - Direction l_dir, t_dir; - shaped_text_get_carets(p_shaped, p_position, l_caret, l_dir, t_caret, t_dir); - - ret["leading_rect"] = l_caret; - ret["leading_direction"] = l_dir; - ret["trailing_rect"] = t_caret; - ret["trailing_direction"] = t_dir; - - return ret; -} + const Glyph *glyphs = shaped_text_get_ellipsis_glyphs(p_shaped); + int gl_size = shaped_text_get_ellipsis_glyph_count(p_shaped); + for (int i = 0; i < gl_size; i++) { + Dictionary glyph; -Array TextServer::_shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const { - Array ret; + glyph["start"] = glyphs[i].start; + glyph["end"] = glyphs[i].end; + glyph["repeat"] = glyphs[i].repeat; + glyph["count"] = glyphs[i].count; + glyph["flags"] = glyphs[i].flags; + glyph["offset"] = Vector2(glyphs[i].x_off, glyphs[i].y_off); + glyph["advance"] = glyphs[i].advance; + glyph["font_rid"] = glyphs[i].font_rid; + glyph["font_size"] = glyphs[i].font_size; + glyph["index"] = glyphs[i].index; - Vector<Vector2> ranges = shaped_text_get_selection(p_shaped, p_start, p_end); - for (int i = 0; i < ranges.size(); i++) { - ret.push_back(ranges[i]); + ret.push_back(glyph); } return ret; } TextServer::TextServer() { + _init_diacritics_map(); } TextServer::~TextServer() { diff --git a/servers/text_server.h b/servers/text_server.h index 62e02e3c97..5c994feaae 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -34,13 +34,14 @@ #include "core/object/ref_counted.h" #include "core/os/os.h" #include "core/templates/rid.h" +#include "core/variant/native_ptr.h" #include "core/variant/variant.h" -#include "scene/resources/texture.h" -class CanvasTexture; +struct Glyph; +struct CaretInfo; -class TextServer : public Object { - GDCLASS(TextServer, Object); +class TextServer : public RefCounted { + GDCLASS(TextServer, RefCounted); public: enum Direction { @@ -63,12 +64,12 @@ public: JUSTIFICATION_CONSTRAIN_ELLIPSIS = 1 << 4, }; - enum LineBreakFlag { + enum LineBreakFlag { // LineBreakFlag can be passed in the same value as the JustificationFlag, do not use the same values. BREAK_NONE = 0, - BREAK_MANDATORY = 1 << 4, - BREAK_WORD_BOUND = 1 << 5, - BREAK_GRAPHEME_BOUND = 1 << 6, - BREAK_WORD_BOUND_ADAPTIVE = 1 << 5 | 1 << 7, + BREAK_MANDATORY = 1 << 5, + BREAK_WORD_BOUND = 1 << 6, + BREAK_GRAPHEME_BOUND = 1 << 7, + BREAK_WORD_BOUND_ADAPTIVE = 1 << 6 | 1 << 8, }; enum TextOverrunFlag { @@ -91,6 +92,7 @@ public: GRAPHEME_IS_ELONGATION = 1 << 7, // Elongation (e.g. kashida), glyph can be duplicated or truncated to fit line to width. GRAPHEME_IS_PUNCTUATION = 1 << 8, // Punctuation, except underscore (can be used as word break, but not line break or justifiction). GRAPHEME_IS_UNDERSCORE = 1 << 9, // Underscore (can be used as word break). + GRAPHEME_IS_CONNECTED = 1 << 10, // Connected to previous grapheme. }; enum Hinting { @@ -123,50 +125,19 @@ public: SPACING_BOTTOM, }; - struct Glyph { - int start = -1; // Start offset in the source string. - int end = -1; // End offset in the source string. - - uint8_t count = 0; // Number of glyphs in the grapheme, set in the first glyph only. - uint8_t repeat = 1; // Draw multiple times in the row. - uint16_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only. - - real_t x_off = 0.f; // Offset from the origin of the glyph on baseline. - real_t y_off = 0.f; - real_t advance = 0.f; // Advance to the next glyph along baseline(x for horizontal layout, y for vertical). - - RID font_rid; // Font resource. - int font_size = 0; // Font size; - int32_t index = 0; // Glyph index (font specific) or UTF-32 codepoint (for the invalid glyphs). - - bool operator==(const Glyph &p_a) const; - bool operator!=(const Glyph &p_a) const; - - bool operator<(const Glyph &p_a) const; - bool operator>(const Glyph &p_a) const; + enum FontStyle { + FONT_BOLD = 1 << 0, + FONT_ITALIC = 1 << 1, + FONT_FIXED_WIDTH = 1 << 2, }; - struct GlyphCompare { // For line breaking reordering. - _FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const { - if (l.start == r.start) { - if (l.count == r.count) { - if ((l.flags & GRAPHEME_IS_VIRTUAL) == GRAPHEME_IS_VIRTUAL) { - return false; - } else { - return true; - } - } - return l.count > r.count; // Sort first glyph with count & flags, order of the rest are irrelevant. - } else { - return l.start < r.start; - } - } - }; + void _draw_hex_code_box_number(RID p_canvas, int p_size, const Vector2 &p_pos, uint8_t p_index, const Color &p_color) const; +protected: struct TrimData { int trim_pos = -1; int ellipsis_pos = -1; - Vector<TextServer::Glyph> ellipsis_glyph_buf; + Vector<Glyph> ellipsis_glyph_buf; }; struct ShapedTextData { @@ -179,6 +150,7 @@ public: int end = 0; // Substring end offset in the parent string. String text; + String custom_punct; TextServer::Direction direction = DIRECTION_LTR; // Desired text direction. TextServer::Orientation orientation = ORIENTATION_HORIZONTAL; @@ -214,45 +186,41 @@ public: bool preserve_invalid = true; // Draw hex code box instead of missing characters. bool preserve_control = false; // Draw control characters. - real_t ascent = 0.f; // Ascent for horizontal layout, 1/2 of width for vertical. - real_t descent = 0.f; // Descent for horizontal layout, 1/2 of width for vertical. - real_t width = 0.f; // Width for horizontal layout, height for vertical. - real_t width_trimmed = 0.f; + float ascent = 0.f; // Ascent for horizontal layout, 1/2 of width for vertical. + float descent = 0.f; // Descent for horizontal layout, 1/2 of width for vertical. + float width = 0.f; // Width for horizontal layout, height for vertical. + float width_trimmed = 0.f; - real_t upos = 0.f; - real_t uthk = 0.f; + float upos = 0.f; + float uthk = 0.f; TrimData overrun_trim_data; bool fit_width_minimum_reached = false; - Vector<TextServer::Glyph> glyphs; - Vector<TextServer::Glyph> glyphs_logical; + Vector<Glyph> glyphs; + Vector<Glyph> glyphs_logical; }; -protected: - static void _bind_methods(); + Map<char32_t, char32_t> diacritics_map; + void _diacritics_map_add(const String &p_from, char32_t p_to); + void _init_diacritics_map(); - static Vector3 hex_code_box_font_size[2]; - static Ref<CanvasTexture> hex_code_box_font_tex[2]; + static void _bind_methods(); public: - static void initialize_hex_code_box_fonts(); - static void finish_hex_code_box_fonts(); - - virtual bool has_feature(Feature p_feature) = 0; + virtual bool has_feature(Feature p_feature) const = 0; virtual String get_name() const = 0; + virtual uint32_t get_features() const = 0; virtual void free(RID p_rid) = 0; virtual bool has(RID p_rid) = 0; virtual bool load_support_data(const String &p_filename) = 0; -#ifdef TOOLS_ENABLED - virtual String get_support_data_filename() = 0; - virtual String get_support_data_info() = 0; - virtual bool save_support_data(const String &p_filename) = 0; -#endif + virtual String get_support_data_filename() const = 0; + virtual String get_support_data_info() const = 0; + virtual bool save_support_data(const String &p_filename) const = 0; - virtual bool is_locale_right_to_left(const String &p_locale) = 0; + virtual bool is_locale_right_to_left(const String &p_locale) const = 0; virtual int32_t name_to_tag(const String &p_name) const { return 0; }; virtual String tag_to_name(int32_t p_tag) const { return ""; }; @@ -263,6 +231,15 @@ public: virtual void font_set_data(RID p_font_rid, const PackedByteArray &p_data) = 0; virtual void font_set_data_ptr(RID p_font_rid, const uint8_t *p_data_ptr, size_t p_data_size) = 0; + virtual void font_set_style(RID p_font_rid, uint32_t /*FontStyle*/ p_style) = 0; + virtual uint32_t /*FontStyle*/ font_get_style(RID p_font_rid) const = 0; + + virtual void font_set_name(RID p_font_rid, const String &p_name) = 0; + virtual String font_get_name(RID p_font_rid) const = 0; + + virtual void font_set_style_name(RID p_font_rid, const String &p_name) = 0; + virtual String font_get_style_name(RID p_font_rid) const = 0; + virtual void font_set_antialiased(RID p_font_rid, bool p_antialiased) = 0; virtual bool font_is_antialiased(RID p_font_rid) const = 0; @@ -281,33 +258,33 @@ public: virtual void font_set_force_autohinter(RID p_font_rid, bool p_force_autohinter) = 0; virtual bool font_is_force_autohinter(RID p_font_rid) const = 0; - virtual void font_set_hinting(RID p_font_rid, TextServer::Hinting p_hinting) = 0; - virtual TextServer::Hinting font_get_hinting(RID p_font_rid) const = 0; + virtual void font_set_hinting(RID p_font_rid, Hinting p_hinting) = 0; + virtual Hinting font_get_hinting(RID p_font_rid) const = 0; virtual void font_set_variation_coordinates(RID p_font_rid, const Dictionary &p_variation_coordinates) = 0; virtual Dictionary font_get_variation_coordinates(RID p_font_rid) const = 0; - virtual void font_set_oversampling(RID p_font_rid, real_t p_oversampling) = 0; - virtual real_t font_get_oversampling(RID p_font_rid) const = 0; + virtual void font_set_oversampling(RID p_font_rid, float p_oversampling) = 0; + virtual float font_get_oversampling(RID p_font_rid) const = 0; virtual Array font_get_size_cache_list(RID p_font_rid) const = 0; virtual void font_clear_size_cache(RID p_font_rid) = 0; virtual void font_remove_size_cache(RID p_font_rid, const Vector2i &p_size) = 0; - virtual void font_set_ascent(RID p_font_rid, int p_size, real_t p_ascent) = 0; - virtual real_t font_get_ascent(RID p_font_rid, int p_size) const = 0; + virtual void font_set_ascent(RID p_font_rid, int p_size, float p_ascent) = 0; + virtual float font_get_ascent(RID p_font_rid, int p_size) const = 0; - virtual void font_set_descent(RID p_font_rid, int p_size, real_t p_descent) = 0; - virtual real_t font_get_descent(RID p_font_rid, int p_size) const = 0; + virtual void font_set_descent(RID p_font_rid, int p_size, float p_descent) = 0; + virtual float font_get_descent(RID p_font_rid, int p_size) const = 0; - virtual void font_set_underline_position(RID p_font_rid, int p_size, real_t p_underline_position) = 0; - virtual real_t font_get_underline_position(RID p_font_rid, int p_size) const = 0; + virtual void font_set_underline_position(RID p_font_rid, int p_size, float p_underline_position) = 0; + virtual float font_get_underline_position(RID p_font_rid, int p_size) const = 0; - virtual void font_set_underline_thickness(RID p_font_rid, int p_size, real_t p_underline_thickness) = 0; - virtual real_t font_get_underline_thickness(RID p_font_rid, int p_size) const = 0; + virtual void font_set_underline_thickness(RID p_font_rid, int p_size, float p_underline_thickness) = 0; + virtual float font_get_underline_thickness(RID p_font_rid, int p_size) const = 0; - virtual void font_set_scale(RID p_font_rid, int p_size, real_t p_scale) = 0; - virtual real_t font_get_scale(RID p_font_rid, int p_size) const = 0; + virtual void font_set_scale(RID p_font_rid, int p_size, float p_scale) = 0; + virtual float font_get_scale(RID p_font_rid, int p_size) const = 0; virtual void font_set_spacing(RID p_font_rid, int p_size, SpacingType p_spacing, int p_value) = 0; virtual int font_get_spacing(RID p_font_rid, int p_size, SpacingType p_spacing) const = 0; @@ -341,7 +318,7 @@ public: virtual int font_get_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph) const = 0; virtual void font_set_glyph_texture_idx(RID p_font_rid, const Vector2i &p_size, int32_t p_glyph, int p_texture_idx) = 0; - virtual bool font_get_glyph_contours(RID p_font, int p_size, int32_t p_index, Vector<Vector3> &r_points, Vector<int32_t> &r_contours, bool &r_orientation) const = 0; + virtual Dictionary font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const = 0; virtual Array font_get_kerning_list(RID p_font_rid, int p_size) const = 0; virtual void font_clear_kerning_map(RID p_font_rid, int p_size) = 0; @@ -376,11 +353,11 @@ public: virtual Dictionary font_supported_feature_list(RID p_font_rid) const = 0; virtual Dictionary font_supported_variation_list(RID p_font_rid) const = 0; - virtual real_t font_get_global_oversampling() const = 0; - virtual void font_set_global_oversampling(real_t p_oversampling) = 0; + virtual float font_get_global_oversampling() const = 0; + virtual void font_set_global_oversampling(float p_oversampling) = 0; - Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const; - void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const; + virtual Vector2 get_hex_code_box_size(int p_size, char32_t p_index) const; + virtual void draw_hex_code_box(RID p_canvas, int p_size, const Vector2 &p_pos, char32_t p_index, const Color &p_color) const; /* Shaped text buffer interface */ @@ -391,7 +368,10 @@ public: virtual void shaped_text_set_direction(RID p_shaped, Direction p_direction = DIRECTION_AUTO) = 0; virtual Direction shaped_text_get_direction(RID p_shaped) const = 0; - virtual void shaped_text_set_bidi_override(RID p_shaped, const Vector<Vector2i> &p_override) = 0; + virtual void shaped_text_set_bidi_override(RID p_shaped, const Array &p_override) = 0; + + virtual void shaped_text_set_custom_punctuation(RID p_shaped, const String &p_punct) = 0; + virtual String shaped_text_get_custom_punctuation(RID p_shaped) const = 0; virtual void shaped_text_set_orientation(RID p_shaped, Orientation p_orientation = ORIENTATION_HORIZONTAL) = 0; virtual Orientation shaped_text_get_orientation(RID p_shaped) const = 0; @@ -409,8 +389,8 @@ public: virtual RID shaped_text_substr(RID p_shaped, int p_start, int p_length) const = 0; // Copy shaped substring (e.g. line break) without reshaping, but correctly reordered, preservers range. virtual RID shaped_text_get_parent(RID p_shaped) const = 0; - virtual real_t shaped_text_fit_to_width(RID p_shaped, real_t p_width, uint8_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) = 0; - virtual real_t shaped_text_tab_align(RID p_shaped, const Vector<real_t> &p_tab_stops) = 0; + virtual float shaped_text_fit_to_width(RID p_shaped, float p_width, uint16_t /*JustificationFlag*/ p_jst_flags = JUSTIFICATION_WORD_BOUND | JUSTIFICATION_KASHIDA) = 0; + virtual float shaped_text_tab_align(RID p_shaped, const PackedFloat32Array &p_tab_stops) = 0; virtual bool shaped_text_shape(RID p_shaped) = 0; virtual bool shaped_text_update_breaks(RID p_shaped) = 0; @@ -418,66 +398,112 @@ public: virtual bool shaped_text_is_ready(RID p_shaped) const = 0; - virtual Vector<Glyph> shaped_text_get_glyphs(RID p_shaped) const = 0; + virtual const Glyph *shaped_text_get_glyphs(RID p_shaped) const = 0; + Array _shaped_text_get_glyphs_wrapper(RID p_shaped) const; + virtual const Glyph *shaped_text_sort_logical(RID p_shaped) = 0; + Array _shaped_text_sort_logical_wrapper(RID p_shaped); + virtual int shaped_text_get_glyph_count(RID p_shaped) const = 0; virtual Vector2i shaped_text_get_range(RID p_shaped) const = 0; - virtual Vector<Glyph> shaped_text_sort_logical(RID p_shaped) = 0; + virtual PackedInt32Array shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start = 0, bool p_once = true, uint16_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; + virtual PackedInt32Array shaped_text_get_line_breaks(RID p_shaped, float p_width, int p_start = 0, uint16_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; + virtual PackedInt32Array shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const; + + virtual int shaped_text_get_trim_pos(RID p_shaped) const = 0; + virtual int shaped_text_get_ellipsis_pos(RID p_shaped) const = 0; + virtual const Glyph *shaped_text_get_ellipsis_glyphs(RID p_shaped) const = 0; + Array _shaped_text_get_ellipsis_glyphs_wrapper(RID p_shaped) const; + virtual int shaped_text_get_ellipsis_glyph_count(RID p_shaped) const = 0; - virtual Vector<Vector2i> shaped_text_get_line_breaks_adv(RID p_shaped, const Vector<real_t> &p_width, int p_start = 0, bool p_once = true, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; - virtual Vector<Vector2i> shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start = 0, uint8_t /*TextBreakFlag*/ p_break_flags = BREAK_MANDATORY | BREAK_WORD_BOUND) const; - virtual Vector<Vector2i> shaped_text_get_word_breaks(RID p_shaped, int p_grapheme_flags = GRAPHEME_IS_SPACE | GRAPHEME_IS_PUNCTUATION) const; + virtual void shaped_text_overrun_trim_to_width(RID p_shaped, float p_width, uint16_t p_trim_flags) = 0; - virtual TrimData shaped_text_get_trim_data(RID p_shaped) const; - virtual void shaped_text_overrun_trim_to_width(RID p_shaped, real_t p_width, uint8_t p_trim_flags) = 0; virtual Array shaped_text_get_objects(RID p_shaped) const = 0; virtual Rect2 shaped_text_get_object_rect(RID p_shaped, Variant p_key) const = 0; virtual Size2 shaped_text_get_size(RID p_shaped) const = 0; - virtual real_t shaped_text_get_ascent(RID p_shaped) const = 0; - virtual real_t shaped_text_get_descent(RID p_shaped) const = 0; - virtual real_t shaped_text_get_width(RID p_shaped) const = 0; - virtual real_t shaped_text_get_underline_position(RID p_shaped) const = 0; - virtual real_t shaped_text_get_underline_thickness(RID p_shaped) const = 0; + virtual float shaped_text_get_ascent(RID p_shaped) const = 0; + virtual float shaped_text_get_descent(RID p_shaped) const = 0; + virtual float shaped_text_get_width(RID p_shaped) const = 0; + virtual float shaped_text_get_underline_position(RID p_shaped) const = 0; + virtual float shaped_text_get_underline_thickness(RID p_shaped) const = 0; + + virtual Direction shaped_text_get_dominant_direction_in_range(RID p_shaped, int p_start, int p_end) const; - virtual Direction shaped_text_get_dominant_direciton_in_range(RID p_shaped, int p_start, int p_end) const; + virtual CaretInfo shaped_text_get_carets(RID p_shaped, int p_position) const; + Dictionary _shaped_text_get_carets_wrapper(RID p_shaped, int p_position) const; - virtual void shaped_text_get_carets(RID p_shaped, int p_position, Rect2 &p_leading_caret, Direction &p_leading_dir, Rect2 &p_trailing_caret, Direction &p_trailing_dir) const; virtual Vector<Vector2> shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const; - virtual int shaped_text_hit_test_grapheme(RID p_shaped, real_t p_coords) const; // Return grapheme index. - virtual int shaped_text_hit_test_position(RID p_shaped, real_t p_coords) const; // Return caret/selection position. + virtual int shaped_text_hit_test_grapheme(RID p_shaped, float p_coords) const; // Return grapheme index. + virtual int shaped_text_hit_test_position(RID p_shaped, float p_coords) const; // Return caret/selection position. - virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos); - virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos); + virtual Vector2 shaped_text_get_grapheme_bounds(RID p_shaped, int p_pos) const; + virtual int shaped_text_next_grapheme_pos(RID p_shaped, int p_pos) const; + virtual int shaped_text_prev_grapheme_pos(RID p_shaped, int p_pos) const; // The pen position is always placed on the baseline and moveing left to right. - virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, real_t p_clip_l = -1.f, real_t p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const; - virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, real_t p_clip_l = -1.f, real_t p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; + virtual void shaped_text_draw(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, const Color &p_color = Color(1, 1, 1)) const; + virtual void shaped_text_draw_outline(RID p_shaped, RID p_canvas, const Vector2 &p_pos, float p_clip_l = -1.f, float p_clip_r = -1.f, int p_outline_size = 1, const Color &p_color = Color(1, 1, 1)) const; // Number conversion. virtual String format_number(const String &p_string, const String &p_language = "") const { return p_string; }; virtual String parse_number(const String &p_string, const String &p_language = "") const { return p_string; }; virtual String percent_sign(const String &p_language = "") const { return "%"; }; - /* GDScript wrappers */ - RID _create_font_memory(const PackedByteArray &p_data, int p_base_size = 16); + virtual String strip_diacritics(const String &p_string) const; + + TextServer(); + ~TextServer(); +}; + +/*************************************************************************/ - Dictionary _font_get_glyph_contours(RID p_font, int p_size, int32_t p_index) const; +struct Glyph { + int start = -1; // Start offset in the source string. + int end = -1; // End offset in the source string. - Array _shaped_text_get_glyphs(RID p_shaped) const; - Dictionary _shaped_text_get_carets(RID p_shaped, int p_position) const; + uint8_t count = 0; // Number of glyphs in the grapheme, set in the first glyph only. + uint8_t repeat = 1; // Draw multiple times in the row. + uint16_t flags = 0; // Grapheme flags (valid, rtl, virtual), set in the first glyph only. - void _shaped_text_set_bidi_override(RID p_shaped, const Array &p_override); + float x_off = 0.f; // Offset from the origin of the glyph on baseline. + float y_off = 0.f; + float advance = 0.f; // Advance to the next glyph along baseline(x for horizontal layout, y for vertical). - Array _shaped_text_get_line_breaks_adv(RID p_shaped, const PackedFloat32Array &p_width, int p_start, bool p_once, uint8_t p_break_flags) const; - Array _shaped_text_get_line_breaks(RID p_shaped, real_t p_width, int p_start, uint8_t p_break_flags) const; - Array _shaped_text_get_word_breaks(RID p_shaped) const; + RID font_rid; // Font resource. + int font_size = 0; // Font size; + int32_t index = 0; // Glyph index (font specific) or UTF-32 codepoint (for the invalid glyphs). - Array _shaped_text_get_selection(RID p_shaped, int p_start, int p_end) const; + bool operator==(const Glyph &p_a) const; + bool operator!=(const Glyph &p_a) const; - TextServer(); - ~TextServer(); + bool operator<(const Glyph &p_a) const; + bool operator>(const Glyph &p_a) const; +}; + +struct CaretInfo { + Rect2 l_caret; + Rect2 t_caret; + TextServer::Direction l_dir; + TextServer::Direction t_dir; +}; + +struct GlyphCompare { // For line breaking reordering. + _FORCE_INLINE_ bool operator()(const Glyph &l, const Glyph &r) const { + if (l.start == r.start) { + if (l.count == r.count) { + if ((l.flags & TextServer::GRAPHEME_IS_VIRTUAL) == TextServer::GRAPHEME_IS_VIRTUAL) { + return false; + } else { + return true; + } + } + return l.count > r.count; // Sort first glyph with count & flags, order of the rest are irrelevant. + } else { + return l.start < r.start; + } + } }; /*************************************************************************/ @@ -485,52 +511,31 @@ public: class TextServerManager : public Object { GDCLASS(TextServerManager, Object); -public: - typedef TextServer *(*CreateFunction)(Error &r_error, void *p_user_data); - protected: static void _bind_methods(); private: static TextServerManager *singleton; - static TextServer *server; - enum { - MAX_SERVERS = 64 - }; - struct TextServerCreate { - String name; - CreateFunction create_function = nullptr; - uint32_t features = 0; - TextServer *instance = nullptr; - void *user_data = nullptr; - }; - - static TextServerCreate server_create_functions[MAX_SERVERS]; - static int server_create_count; + Ref<TextServer> primary_interface; + Vector<Ref<TextServer>> interfaces; public: _FORCE_INLINE_ static TextServerManager *get_singleton() { return singleton; } - static void register_create_function(const String &p_name, uint32_t p_features, CreateFunction p_function, void *p_user_data); - static int get_interface_count(); - static String get_interface_name(int p_index); - static uint32_t get_interface_features(int p_index); - static TextServer *initialize(int p_index, Error &r_error); - static TextServer *get_primary_interface(); - - /* GDScript wrappers */ - int _get_interface_count() const; - String _get_interface_name(int p_index) const; - uint32_t _get_interface_features(int p_index) const; - TextServer *_get_interface(int p_index) const; - Array _get_interfaces() const; - TextServer *_find_interface(const String &p_name) const; + void add_interface(const Ref<TextServer> &p_interface); + void remove_interface(const Ref<TextServer> &p_interface); + int get_interface_count() const; + Ref<TextServer> get_interface(int p_index) const; + Ref<TextServer> find_interface(const String &p_name) const; + Array get_interfaces() const; - bool _set_primary_interface(int p_index); - TextServer *_get_primary_interface() const; + _FORCE_INLINE_ Ref<TextServer> get_primary_interface() const { + return primary_interface; + } + void set_primary_interface(const Ref<TextServer> &p_primary_interface); TextServerManager(); ~TextServerManager(); @@ -538,7 +543,7 @@ public: /*************************************************************************/ -#define TS TextServerManager::get_primary_interface() +#define TS TextServerManager::get_singleton()->get_primary_interface() VARIANT_ENUM_CAST(TextServer::Direction); VARIANT_ENUM_CAST(TextServer::Orientation); @@ -550,5 +555,10 @@ VARIANT_ENUM_CAST(TextServer::Hinting); VARIANT_ENUM_CAST(TextServer::Feature); VARIANT_ENUM_CAST(TextServer::ContourPointTag); VARIANT_ENUM_CAST(TextServer::SpacingType); +VARIANT_ENUM_CAST(TextServer::FontStyle); + +GDVIRTUAL_NATIVE_PTR(Glyph); +GDVIRTUAL_NATIVE_PTR(Glyph *); +GDVIRTUAL_NATIVE_PTR(CaretInfo); #endif // TEXT_SERVER_H diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp index fc1d82a964..ca11df439c 100644 --- a/servers/xr/xr_interface.cpp +++ b/servers/xr/xr_interface.cpp @@ -29,9 +29,11 @@ /*************************************************************************/ #include "xr_interface.h" -#include "servers/rendering/renderer_compositor.h" +// #include "servers/rendering/renderer_compositor.h" void XRInterface::_bind_methods() { + ADD_SIGNAL(MethodInfo("play_area_changed", PropertyInfo(Variant::INT, "mode"))); + ClassDB::bind_method(D_METHOD("get_name"), &XRInterface::get_name); ClassDB::bind_method(D_METHOD("get_capabilities"), &XRInterface::get_capabilities); @@ -47,12 +49,21 @@ void XRInterface::_bind_methods() { ClassDB::bind_method(D_METHOD("get_render_target_size"), &XRInterface::get_render_target_size); ClassDB::bind_method(D_METHOD("get_view_count"), &XRInterface::get_view_count); + ClassDB::bind_method(D_METHOD("trigger_haptic_pulse", "action_name", "tracker_name", "frequency", "amplitude", "duration_sec", "delay_sec"), &XRInterface::trigger_haptic_pulse); + ADD_GROUP("Interface", "interface_"); ADD_PROPERTY(PropertyInfo(Variant::BOOL, "interface_is_primary"), "set_primary", "is_primary"); - // we don't have any properties specific to VR yet.... + // methods and properties specific to VR... + ClassDB::bind_method(D_METHOD("supports_play_area_mode", "mode"), &XRInterface::supports_play_area_mode); + ClassDB::bind_method(D_METHOD("get_play_area_mode"), &XRInterface::get_play_area_mode); + ClassDB::bind_method(D_METHOD("set_play_area_mode", "mode"), &XRInterface::set_play_area_mode); + ClassDB::bind_method(D_METHOD("get_play_area"), &XRInterface::get_play_area); + + ADD_GROUP("XR", "xr_"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "xr_play_area_mode", PROPERTY_HINT_ENUM, "Unknown,3DOF,Sitting,Roomscale,Stage"), "set_play_area_mode", "get_play_area_mode"); - // but we do have properties specific to AR.... + // methods and properties specific to AR.... ClassDB::bind_method(D_METHOD("get_anchor_detection_is_enabled"), &XRInterface::get_anchor_detection_is_enabled); ClassDB::bind_method(D_METHOD("set_anchor_detection_is_enabled", "enable"), &XRInterface::set_anchor_detection_is_enabled); ClassDB::bind_method(D_METHOD("get_camera_feed_id"), &XRInterface::get_camera_feed_id); @@ -63,19 +74,23 @@ void XRInterface::_bind_methods() { BIND_ENUM_CONSTANT(XR_NONE); BIND_ENUM_CONSTANT(XR_MONO); BIND_ENUM_CONSTANT(XR_STEREO); + BIND_ENUM_CONSTANT(XR_QUAD); + BIND_ENUM_CONSTANT(XR_VR); BIND_ENUM_CONSTANT(XR_AR); BIND_ENUM_CONSTANT(XR_EXTERNAL); - BIND_ENUM_CONSTANT(EYE_MONO); - BIND_ENUM_CONSTANT(EYE_LEFT); - BIND_ENUM_CONSTANT(EYE_RIGHT); - BIND_ENUM_CONSTANT(XR_NORMAL_TRACKING); BIND_ENUM_CONSTANT(XR_EXCESSIVE_MOTION); BIND_ENUM_CONSTANT(XR_INSUFFICIENT_FEATURES); BIND_ENUM_CONSTANT(XR_UNKNOWN_TRACKING); BIND_ENUM_CONSTANT(XR_NOT_TRACKING); -} + + BIND_ENUM_CONSTANT(XR_PLAY_AREA_UNKNOWN); + BIND_ENUM_CONSTANT(XR_PLAY_AREA_3DOF); + BIND_ENUM_CONSTANT(XR_PLAY_AREA_SITTING); + BIND_ENUM_CONSTANT(XR_PLAY_AREA_ROOMSCALE); + BIND_ENUM_CONSTANT(XR_PLAY_AREA_STAGE); +}; bool XRInterface::is_primary() { XRServer *xr_server = XRServer::get_singleton(); @@ -101,6 +116,29 @@ XRInterface::XRInterface() {} XRInterface::~XRInterface() {} +// query if this interface supports this play area mode +bool XRInterface::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) { + return p_mode == XR_PLAY_AREA_UNKNOWN; +} + +// get the current play area mode +XRInterface::PlayAreaMode XRInterface::get_play_area_mode() const { + return XR_PLAY_AREA_UNKNOWN; +} + +// change the play area mode, note that this should return false if the mode is not available +bool XRInterface::set_play_area_mode(XRInterface::PlayAreaMode p_mode) { + return p_mode == XR_PLAY_AREA_UNKNOWN; +} + +// if available, returns an array of vectors denoting the play area the player can move around in +PackedVector3Array XRInterface::get_play_area() const { + // Return an empty array by default. + // Note implementation is responsible for applying our reference frame and world scale to the raw data. + // `play_area_changed` should be emitted if play area data is available and either the reference frame or world scale changes. + return PackedVector3Array(); +}; + /** these will only be implemented on AR interfaces, so we want dummies for VR **/ bool XRInterface::get_anchor_detection_is_enabled() const { return false; @@ -114,9 +152,24 @@ int XRInterface::get_camera_feed_id() { } /** these are optional, so we want dummies **/ +PackedStringArray XRInterface::get_suggested_tracker_names() const { + PackedStringArray arr; + + return arr; +} + +PackedStringArray XRInterface::get_suggested_pose_names(const StringName &p_tracker_name) const { + PackedStringArray arr; + + return arr; +} + XRInterface::TrackingStatus XRInterface::get_tracking_status() const { return XR_UNKNOWN_TRACKING; } void XRInterface::notification(int p_what) { } + +void XRInterface::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) { +} diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h index 4f5d4bad10..b489481f75 100644 --- a/servers/xr/xr_interface.h +++ b/servers/xr/xr_interface.h @@ -58,14 +58,10 @@ public: XR_NONE = 0, /* no capabilities */ XR_MONO = 1, /* can be used with mono output */ XR_STEREO = 2, /* can be used with stereo output */ - XR_AR = 4, /* offers a camera feed for AR */ - XR_EXTERNAL = 8 /* renders to external device */ - }; - - enum Eyes { - EYE_MONO, /* my son says we should call this EYE_CYCLOPS */ - EYE_LEFT, - EYE_RIGHT + XR_QUAD = 4, /* can be used with quad output (not currently supported) */ + XR_VR = 8, /* offers VR support */ + XR_AR = 16, /* offers AR support */ + XR_EXTERNAL = 32 /* renders to external device */ }; enum TrackingStatus { /* tracking status currently based on AR but we can start doing more with this for VR as well */ @@ -76,7 +72,14 @@ public: XR_NOT_TRACKING }; -private: + enum PlayAreaMode { /* defines the mode used by the XR interface for tracking */ + XR_PLAY_AREA_UNKNOWN, /* Area mode not set or not available */ + XR_PLAY_AREA_3DOF, /* Only support orientation tracking, no positional tracking, area will center around player */ + XR_PLAY_AREA_SITTING, /* Player is in seated position, limited positional tracking, fixed guardian around player */ + XR_PLAY_AREA_ROOMSCALE, /* Player is free to move around, full positional tracking */ + XR_PLAY_AREA_STAGE, /* Same as roomscale but origin point is fixed to the center of the physical space, XRServer.center_on_hmd disabled */ + }; + protected: _THREAD_SAFE_CLASS_ @@ -94,10 +97,18 @@ public: virtual bool initialize() = 0; /* initialize this interface, if this has an HMD it becomes the primary interface */ virtual void uninitialize() = 0; /* deinitialize this interface */ + /** input and output **/ + + virtual PackedStringArray get_suggested_tracker_names() const; /* return a list of likely/suggested tracker names */ + virtual PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const; /* return a list of likely/suggested action names for this tracker */ virtual TrackingStatus get_tracking_status() const; /* get the status of our current tracking */ + virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0); /* trigger a haptic pulse */ /** specific to VR **/ - // nothing yet + virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode); /* query if this interface supports this play area mode */ + virtual XRInterface::PlayAreaMode get_play_area_mode() const; /* get the current play area mode */ + virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode); /* change the play area mode, note that this should return false if the mode is not available */ + virtual PackedVector3Array get_play_area() const; /* if available, returns an array of vectors denoting the play area the player can move around in */ /** specific to AR **/ virtual bool get_anchor_detection_is_enabled() const; @@ -110,7 +121,7 @@ public: virtual uint32_t get_view_count() = 0; /* returns the view count we need (1 is monoscopic, 2 is stereoscopic but can be more) */ virtual Transform3D get_camera_transform() = 0; /* returns the position of our camera for updating our camera node. For monoscopic this is equal to the views transform, for stereoscopic this should be an average */ virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) = 0; /* get each views transform */ - virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each view projection matrix */ + virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) = 0; /* get each view projection matrix */ // note, external color/depth/vrs texture support will be added here soon. @@ -124,7 +135,7 @@ public: }; VARIANT_ENUM_CAST(XRInterface::Capabilities); -VARIANT_ENUM_CAST(XRInterface::Eyes); VARIANT_ENUM_CAST(XRInterface::TrackingStatus); +VARIANT_ENUM_CAST(XRInterface::PlayAreaMode); #endif // !XR_INTERFACE_H diff --git a/servers/xr/xr_interface_extension.cpp b/servers/xr/xr_interface_extension.cpp index e1519d1463..80576ac607 100644 --- a/servers/xr/xr_interface_extension.cpp +++ b/servers/xr/xr_interface_extension.cpp @@ -29,7 +29,9 @@ /*************************************************************************/ #include "xr_interface_extension.h" -#include "servers/rendering/renderer_compositor.h" +#include "servers/rendering/renderer_rd/renderer_storage_rd.h" +#include "servers/rendering/renderer_storage.h" +#include "servers/rendering/rendering_server_globals.h" void XRInterfaceExtension::_bind_methods() { GDVIRTUAL_BIND(_get_name); @@ -39,9 +41,10 @@ void XRInterfaceExtension::_bind_methods() { GDVIRTUAL_BIND(_initialize); GDVIRTUAL_BIND(_uninitialize); - GDVIRTUAL_BIND(_get_tracking_status); - - ClassDB::bind_method(D_METHOD("add_blit", "render_target", "rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit); + GDVIRTUAL_BIND(_supports_play_area_mode, "mode"); + GDVIRTUAL_BIND(_get_play_area_mode); + GDVIRTUAL_BIND(_set_play_area_mode, "mode"); + GDVIRTUAL_BIND(_get_play_area); GDVIRTUAL_BIND(_get_render_target_size); GDVIRTUAL_BIND(_get_view_count); @@ -49,17 +52,29 @@ void XRInterfaceExtension::_bind_methods() { GDVIRTUAL_BIND(_get_transform_for_view, "view", "cam_transform"); GDVIRTUAL_BIND(_get_projection_for_view, "view", "aspect", "z_near", "z_far"); - GDVIRTUAL_BIND(_commit_views); + GDVIRTUAL_BIND(_commit_views, "render_target", "screen_rect"); GDVIRTUAL_BIND(_process); GDVIRTUAL_BIND(_notification, "what"); + /** input and output **/ + + GDVIRTUAL_BIND(_get_suggested_tracker_names); + GDVIRTUAL_BIND(_get_suggested_pose_names, "tracker_name"); + GDVIRTUAL_BIND(_get_tracking_status); + GDVIRTUAL_BIND(_trigger_haptic_pulse, "action_name", "tracker_name", "frequency", "amplitude", "duration_sec", "delay_sec"); + // we don't have any properties specific to VR yet.... // but we do have properties specific to AR.... GDVIRTUAL_BIND(_get_anchor_detection_is_enabled); GDVIRTUAL_BIND(_set_anchor_detection_is_enabled, "enabled"); GDVIRTUAL_BIND(_get_camera_feed_id); + + // helper methods + ClassDB::bind_method(D_METHOD("add_blit", "render_target", "src_rect", "dst_rect", "use_layer", "layer", "apply_lens_distortion", "eye_center", "k1", "k2", "upscale", "aspect_ratio"), &XRInterfaceExtension::add_blit); + ClassDB::bind_method(D_METHOD("get_render_target_texture", "render_target"), &XRInterfaceExtension::get_render_target_texture); + // ClassDB::bind_method(D_METHOD("get_render_target_depth", "render_target"), &XRInterfaceExtension::get_render_target_depth); } StringName XRInterfaceExtension::get_name() const { @@ -106,6 +121,22 @@ void XRInterfaceExtension::uninitialize() { GDVIRTUAL_CALL(_uninitialize); } +PackedStringArray XRInterfaceExtension::get_suggested_tracker_names() const { + PackedStringArray arr; + + GDVIRTUAL_CALL(_get_suggested_tracker_names, arr); + + return arr; +} + +PackedStringArray XRInterfaceExtension::get_suggested_pose_names(const StringName &p_tracker_name) const { + PackedStringArray arr; + + GDVIRTUAL_CALL(_get_suggested_pose_names, p_tracker_name, arr); + + return arr; +} + XRInterface::TrackingStatus XRInterfaceExtension::get_tracking_status() const { uint32_t status; @@ -116,6 +147,48 @@ XRInterface::TrackingStatus XRInterfaceExtension::get_tracking_status() const { return XR_UNKNOWN_TRACKING; } +void XRInterfaceExtension::trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec) { + GDVIRTUAL_CALL(_trigger_haptic_pulse, p_action_name, p_tracker_name, p_frequency, p_amplitude, p_duration_sec, p_delay_sec); +} + +bool XRInterfaceExtension::supports_play_area_mode(XRInterface::PlayAreaMode p_mode) { + bool is_supported; + + if (GDVIRTUAL_CALL(_supports_play_area_mode, p_mode, is_supported)) { + return is_supported; + } + + return false; +} + +XRInterface::PlayAreaMode XRInterfaceExtension::get_play_area_mode() const { + uint32_t mode; + + if (GDVIRTUAL_CALL(_get_play_area_mode, mode)) { + return XRInterface::PlayAreaMode(mode); + } + + return XRInterface::XR_PLAY_AREA_UNKNOWN; +} + +bool XRInterfaceExtension::set_play_area_mode(XRInterface::PlayAreaMode p_mode) { + bool success; + + if (GDVIRTUAL_CALL(_set_play_area_mode, p_mode, success)) { + return success; + } + + return false; +} + +PackedVector3Array XRInterfaceExtension::get_play_area() const { + PackedVector3Array arr; + + GDVIRTUAL_CALL(_get_play_area, arr); + + return arr; +} + /** these will only be implemented on AR interfaces, so we want dummies for VR **/ bool XRInterfaceExtension::get_anchor_detection_is_enabled() const { bool enabled; @@ -182,7 +255,7 @@ Transform3D XRInterfaceExtension::get_transform_for_view(uint32_t p_view, const return Transform3D(); } -CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) { +CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) { CameraMatrix cm; PackedFloat64Array arr; @@ -198,13 +271,14 @@ CameraMatrix XRInterfaceExtension::get_projection_for_view(uint32_t p_view, real return CameraMatrix(); } -void XRInterfaceExtension::add_blit(RID p_render_target, Rect2i p_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, float p_k1, float p_k2, float p_upscale, float p_aspect_ratio) { +void XRInterfaceExtension::add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer, uint32_t p_layer, bool p_apply_lens_distortion, Vector2 p_eye_center, double p_k1, double p_k2, double p_upscale, double p_aspect_ratio) { BlitToScreen blit; ERR_FAIL_COND_MSG(!can_add_blits, "add_blit can only be called from an XR plugin from within _commit_views!"); blit.render_target = p_render_target; - blit.rect = p_rect; + blit.src_rect = p_src_rect; + blit.dst_rect = p_dst_rect; blit.multi_view.use_layer = p_use_layer; blit.multi_view.layer = p_layer; @@ -239,3 +313,23 @@ void XRInterfaceExtension::process() { void XRInterfaceExtension::notification(int p_what) { GDVIRTUAL_CALL(_notification, p_what); } + +RID XRInterfaceExtension::get_render_target_texture(RID p_render_target) { + // In due time this will need to be enhance to return the correct INTERNAL RID for the chosen rendering engine. + // So once a GLES driver is implemented we'll return that and the implemented plugin needs to handle this correctly too. + RendererStorageRD *rd_storage = RendererStorageRD::base_singleton; + ERR_FAIL_NULL_V_MSG(rd_storage, RID(), "Renderer storage not setup"); + + return rd_storage->render_target_get_rd_texture(p_render_target); +} + +/* +RID XRInterfaceExtension::get_render_target_depth(RID p_render_target) { + // TODO implement this, the problem is that our depth texture isn't part of our render target as it is used for 3D rendering only + // but we don't have access to our render buffers from here.... + RendererSceneRenderRD * rd_scene = ?????; + ERR_FAIL_NULL_V_MSG(rd_scene, RID(), "Renderer scene render not setup"); + + return rd_scene->render_buffers_get_depth_texture(????????????); +} +*/ diff --git a/servers/xr/xr_interface_extension.h b/servers/xr/xr_interface_extension.h index ab4d90bfe6..763526de96 100644 --- a/servers/xr/xr_interface_extension.h +++ b/servers/xr/xr_interface_extension.h @@ -62,11 +62,28 @@ public: GDVIRTUAL0R(bool, _initialize); GDVIRTUAL0(_uninitialize); + /** input and output **/ + + virtual PackedStringArray get_suggested_tracker_names() const override; /* return a list of likely/suggested tracker names */ + virtual PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const override; /* return a list of likely/suggested action names for this tracker */ virtual TrackingStatus get_tracking_status() const override; + virtual void trigger_haptic_pulse(const String &p_action_name, const StringName &p_tracker_name, double p_frequency, double p_amplitude, double p_duration_sec, double p_delay_sec = 0) override; + + GDVIRTUAL0RC(PackedStringArray, _get_suggested_tracker_names); + GDVIRTUAL1RC(PackedStringArray, _get_suggested_pose_names, const StringName &); GDVIRTUAL0RC(uint32_t, _get_tracking_status); + GDVIRTUAL6(_trigger_haptic_pulse, const String &, const StringName &, double, double, double, double); /** specific to VR **/ - // nothing yet + virtual bool supports_play_area_mode(XRInterface::PlayAreaMode p_mode) override; /* query if this interface supports this play area mode */ + virtual XRInterface::PlayAreaMode get_play_area_mode() const override; /* get the current play area mode */ + virtual bool set_play_area_mode(XRInterface::PlayAreaMode p_mode) override; /* change the play area mode, note that this should return false if the mode is not available */ + virtual PackedVector3Array get_play_area() const override; /* if available, returns an array of vectors denoting the play area the player can move around in */ + + GDVIRTUAL1RC(bool, _supports_play_area_mode, XRInterface::PlayAreaMode); + GDVIRTUAL0RC(uint32_t, _get_play_area_mode); + GDVIRTUAL1RC(bool, _set_play_area_mode, uint32_t); + GDVIRTUAL0RC(PackedVector3Array, _get_play_area); /** specific to AR **/ virtual bool get_anchor_detection_is_enabled() const override; @@ -83,15 +100,15 @@ public: virtual uint32_t get_view_count() override; virtual Transform3D get_camera_transform() override; virtual Transform3D get_transform_for_view(uint32_t p_view, const Transform3D &p_cam_transform) override; - virtual CameraMatrix get_projection_for_view(uint32_t p_view, real_t p_aspect, real_t p_z_near, real_t p_z_far) override; + virtual CameraMatrix get_projection_for_view(uint32_t p_view, double p_aspect, double p_z_near, double p_z_far) override; GDVIRTUAL0R(Size2, _get_render_target_size); GDVIRTUAL0R(uint32_t, _get_view_count); GDVIRTUAL0R(Transform3D, _get_camera_transform); GDVIRTUAL2R(Transform3D, _get_transform_for_view, uint32_t, const Transform3D &); - GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, real_t, real_t, real_t); + GDVIRTUAL4R(PackedFloat64Array, _get_projection_for_view, uint32_t, double, double, double); - void add_blit(RID p_render_target, Rect2i p_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), float p_k1 = 0.0, float p_k2 = 0.0, float p_upscale = 1.0, float p_aspect_ratio = 1.0); + void add_blit(RID p_render_target, Rect2 p_src_rect, Rect2i p_dst_rect, bool p_use_layer = false, uint32_t p_layer = 0, bool p_apply_lens_distortion = false, Vector2 p_eye_center = Vector2(), double p_k1 = 0.0, double p_k2 = 0.0, double p_upscale = 1.0, double p_aspect_ratio = 1.0); virtual Vector<BlitToScreen> commit_views(RID p_render_target, const Rect2 &p_screen_rect) override; GDVIRTUAL2(_commit_views, RID, const Rect2 &); @@ -100,6 +117,10 @@ public: GDVIRTUAL0(_process); GDVIRTUAL1(_notification, int); + + /* access to some internals we need */ + RID get_render_target_texture(RID p_render_target); + // RID get_render_target_depth(RID p_render_target); }; #endif // !XR_INTERFACE_EXTENSION_H diff --git a/servers/xr/xr_pose.cpp b/servers/xr/xr_pose.cpp new file mode 100644 index 0000000000..0d05e62b46 --- /dev/null +++ b/servers/xr/xr_pose.cpp @@ -0,0 +1,110 @@ +/*************************************************************************/ +/* xr_pose.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "xr_pose.h" + +#include "servers/xr_server.h" + +void XRPose::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_has_tracking_data", "has_tracking_data"), &XRPose::set_has_tracking_data); + ClassDB::bind_method(D_METHOD("get_has_tracking_data"), &XRPose::get_has_tracking_data); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "has_tracking_data"), "set_has_tracking_data", "get_has_tracking_data"); + + ClassDB::bind_method(D_METHOD("set_name", "name"), &XRPose::set_name); + ClassDB::bind_method(D_METHOD("get_name"), &XRPose::get_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_name", "get_name"); + + ClassDB::bind_method(D_METHOD("set_transform", "transform"), &XRPose::set_transform); + ClassDB::bind_method(D_METHOD("get_transform"), &XRPose::get_transform); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "transform"), "set_transform", "get_transform"); + ClassDB::bind_method(D_METHOD("get_adjusted_transform"), &XRPose::get_adjusted_transform); + + ClassDB::bind_method(D_METHOD("set_linear_velocity", "velocity"), &XRPose::set_linear_velocity); + ClassDB::bind_method(D_METHOD("get_linear_velocity"), &XRPose::get_linear_velocity); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "linear_velocity"), "set_linear_velocity", "get_linear_velocity"); + + ClassDB::bind_method(D_METHOD("set_angular_velocity", "velocity"), &XRPose::set_angular_velocity); + ClassDB::bind_method(D_METHOD("get_angular_velocity"), &XRPose::get_angular_velocity); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "angular_velocity"), "set_angular_velocity", "get_angular_velocity"); +} + +void XRPose::set_has_tracking_data(const bool p_has_tracking_data) { + has_tracking_data = p_has_tracking_data; +} +bool XRPose::get_has_tracking_data() const { + return has_tracking_data; +} + +void XRPose::set_name(const StringName &p_name) { + name = p_name; +} + +StringName XRPose::get_name() const { + return name; +} + +void XRPose::set_transform(const Transform3D p_transform) { + transform = p_transform; +} + +Transform3D XRPose::get_transform() const { + return transform; +} + +Transform3D XRPose::get_adjusted_transform() const { + Transform3D adjusted_transform = transform; + + XRServer *xr_server = XRServer::get_singleton(); + ERR_FAIL_NULL_V(xr_server, transform); + + // apply world scale + adjusted_transform.origin *= xr_server->get_world_scale(); + + // apply reference frame + adjusted_transform = xr_server->get_reference_frame() * adjusted_transform; + + return adjusted_transform; +} + +void XRPose::set_linear_velocity(const Vector3 p_velocity) { + linear_velocity = p_velocity; +} + +Vector3 XRPose::get_linear_velocity() const { + return linear_velocity; +} + +void XRPose::set_angular_velocity(const Vector3 p_velocity) { + angular_velocity = p_velocity; +} + +Vector3 XRPose::get_angular_velocity() const { + return angular_velocity; +} diff --git a/servers/xr/xr_pose.h b/servers/xr/xr_pose.h new file mode 100644 index 0000000000..223e95ddfe --- /dev/null +++ b/servers/xr/xr_pose.h @@ -0,0 +1,68 @@ +/*************************************************************************/ +/* xr_pose.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef XR_POSE_H +#define XR_POSE_H + +#include "core/object/ref_counted.h" + +class XRPose : public RefCounted { + GDCLASS(XRPose, RefCounted); + +public: +private: + bool has_tracking_data = false; + StringName name; + Transform3D transform; + Vector3 linear_velocity; + Vector3 angular_velocity; + +protected: + static void _bind_methods(); + +public: + void set_has_tracking_data(const bool p_has_tracking_data); + bool get_has_tracking_data() const; + + void set_name(const StringName &p_name); + StringName get_name() const; + + void set_transform(const Transform3D p_transform); + Transform3D get_transform() const; + Transform3D get_adjusted_transform() const; + + void set_linear_velocity(const Vector3 p_velocity); + Vector3 get_linear_velocity() const; + + void set_angular_velocity(const Vector3 p_velocity); + Vector3 get_angular_velocity() const; +}; + +#endif diff --git a/servers/xr/xr_positional_tracker.cpp b/servers/xr/xr_positional_tracker.cpp index e9383db941..1313a91172 100644 --- a/servers/xr/xr_positional_tracker.cpp +++ b/servers/xr/xr_positional_tracker.cpp @@ -37,29 +37,37 @@ void XRPositionalTracker::_bind_methods() { BIND_ENUM_CONSTANT(TRACKER_HAND_LEFT); BIND_ENUM_CONSTANT(TRACKER_HAND_RIGHT); - // this class is read only from GDScript, so we only have access to getters.. ClassDB::bind_method(D_METHOD("get_tracker_type"), &XRPositionalTracker::get_tracker_type); - ClassDB::bind_method(D_METHOD("get_tracker_id"), &XRPositionalTracker::get_tracker_id); + ClassDB::bind_method(D_METHOD("set_tracker_type", "type"), &XRPositionalTracker::set_tracker_type); + ADD_PROPERTY(PropertyInfo(Variant::INT, "type"), "set_tracker_type", "get_tracker_type"); + ClassDB::bind_method(D_METHOD("get_tracker_name"), &XRPositionalTracker::get_tracker_name); - ClassDB::bind_method(D_METHOD("get_joy_id"), &XRPositionalTracker::get_joy_id); - ClassDB::bind_method(D_METHOD("is_tracking_orientation"), &XRPositionalTracker::is_tracking_orientation); - ClassDB::bind_method(D_METHOD("get_orientation"), &XRPositionalTracker::get_orientation); - ClassDB::bind_method(D_METHOD("is_tracking_position"), &XRPositionalTracker::is_tracking_position); - ClassDB::bind_method(D_METHOD("get_position"), &XRPositionalTracker::get_position); + ClassDB::bind_method(D_METHOD("set_tracker_name", "name"), &XRPositionalTracker::set_tracker_name); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "name"), "set_tracker_name", "get_tracker_name"); + + ClassDB::bind_method(D_METHOD("get_tracker_desc"), &XRPositionalTracker::get_tracker_desc); + ClassDB::bind_method(D_METHOD("set_tracker_desc", "description"), &XRPositionalTracker::set_tracker_desc); + ADD_PROPERTY(PropertyInfo(Variant::STRING, "description"), "set_tracker_desc", "get_tracker_desc"); + ClassDB::bind_method(D_METHOD("get_tracker_hand"), &XRPositionalTracker::get_tracker_hand); - ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &XRPositionalTracker::get_transform); - ClassDB::bind_method(D_METHOD("get_mesh"), &XRPositionalTracker::get_mesh); - - // these functions we don't want to expose to normal users but do need to be callable from GDNative - ClassDB::bind_method(D_METHOD("_set_tracker_type", "type"), &XRPositionalTracker::set_tracker_type); - ClassDB::bind_method(D_METHOD("_set_tracker_name", "name"), &XRPositionalTracker::set_tracker_name); - ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &XRPositionalTracker::set_joy_id); - ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &XRPositionalTracker::set_orientation); - ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &XRPositionalTracker::set_rw_position); - ClassDB::bind_method(D_METHOD("_set_mesh", "mesh"), &XRPositionalTracker::set_mesh); + ClassDB::bind_method(D_METHOD("set_tracker_hand", "hand"), &XRPositionalTracker::set_tracker_hand); + ADD_PROPERTY(PropertyInfo(Variant::INT, "hand", PROPERTY_HINT_ENUM, "Unknown,Left,Right"), "set_tracker_hand", "get_tracker_hand"); + + ClassDB::bind_method(D_METHOD("has_pose", "name"), &XRPositionalTracker::has_pose); + ClassDB::bind_method(D_METHOD("get_pose", "name"), &XRPositionalTracker::get_pose); + ClassDB::bind_method(D_METHOD("invalidate_pose", "name"), &XRPositionalTracker::invalidate_pose); + ClassDB::bind_method(D_METHOD("set_pose", "name", "transform", "linear_velocity", "angular_velocity"), &XRPositionalTracker::set_pose); + ADD_SIGNAL(MethodInfo("pose_changed", PropertyInfo(Variant::OBJECT, "pose", PROPERTY_HINT_RESOURCE_TYPE, "XRPose"))); + + ClassDB::bind_method(D_METHOD("get_input", "name"), &XRPositionalTracker::get_input); + ClassDB::bind_method(D_METHOD("set_input", "name", "value"), &XRPositionalTracker::set_input); + ADD_SIGNAL(MethodInfo("button_pressed", PropertyInfo(Variant::STRING, "name"))); + ADD_SIGNAL(MethodInfo("button_released", PropertyInfo(Variant::STRING, "name"))); + ADD_SIGNAL(MethodInfo("input_value_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::FLOAT, "value"))); + ADD_SIGNAL(MethodInfo("input_axis_changed", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::VECTOR2, "vector"))); + ClassDB::bind_method(D_METHOD("get_rumble"), &XRPositionalTracker::get_rumble); ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &XRPositionalTracker::set_rumble); - ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "rumble"), "set_rumble", "get_rumble"); }; @@ -67,13 +75,6 @@ void XRPositionalTracker::set_tracker_type(XRServer::TrackerType p_type) { if (type != p_type) { type = p_type; hand = XRPositionalTracker::TRACKER_HAND_UNKNOWN; - - XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL(xr_server); - - // get a tracker id for our type - // note if this is a controller this will be 3 or higher but we may change it later. - tracker_id = xr_server->get_free_tracker_id_for_type(p_type); }; }; @@ -81,7 +82,8 @@ XRServer::TrackerType XRPositionalTracker::get_tracker_type() const { return type; }; -void XRPositionalTracker::set_tracker_name(const String &p_name) { +void XRPositionalTracker::set_tracker_name(const StringName &p_name) { + // Note: this should not be changed after the tracker is registered with the XRServer! name = p_name; }; @@ -89,85 +91,13 @@ StringName XRPositionalTracker::get_tracker_name() const { return name; }; -int XRPositionalTracker::get_tracker_id() const { - return tracker_id; -}; - -void XRPositionalTracker::set_joy_id(int p_joy_id) { - joy_id = p_joy_id; -}; - -int XRPositionalTracker::get_joy_id() const { - return joy_id; -}; - -bool XRPositionalTracker::is_tracking_orientation() const { - return tracking_orientation; -}; - -void XRPositionalTracker::set_orientation(const Basis &p_orientation) { - _THREAD_SAFE_METHOD_ - - tracking_orientation = true; // obviously we have this - orientation = p_orientation; -}; - -Basis XRPositionalTracker::get_orientation() const { - _THREAD_SAFE_METHOD_ - - return orientation; -}; - -bool XRPositionalTracker::is_tracking_position() const { - return tracking_position; -}; - -void XRPositionalTracker::set_position(const Vector3 &p_position) { - _THREAD_SAFE_METHOD_ - - XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL(xr_server); - real_t world_scale = xr_server->get_world_scale(); - ERR_FAIL_COND(world_scale == 0); - - tracking_position = true; // obviously we have this - rw_position = p_position / world_scale; -}; - -Vector3 XRPositionalTracker::get_position() const { - _THREAD_SAFE_METHOD_ - - XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL_V(xr_server, rw_position); - real_t world_scale = xr_server->get_world_scale(); - - return rw_position * world_scale; -}; - -void XRPositionalTracker::set_rw_position(const Vector3 &p_rw_position) { - _THREAD_SAFE_METHOD_ - - tracking_position = true; // obviously we have this - rw_position = p_rw_position; -}; - -Vector3 XRPositionalTracker::get_rw_position() const { - _THREAD_SAFE_METHOD_ - - return rw_position; -}; - -void XRPositionalTracker::set_mesh(const Ref<Mesh> &p_mesh) { - _THREAD_SAFE_METHOD_ - - mesh = p_mesh; -}; - -Ref<Mesh> XRPositionalTracker::get_mesh() const { - _THREAD_SAFE_METHOD_ +void XRPositionalTracker::set_tracker_desc(const String &p_desc) { + description = p_desc; +} - return mesh; -}; +String XRPositionalTracker::get_tracker_desc() const { + return description; +} XRPositionalTracker::TrackerHand XRPositionalTracker::get_tracker_hand() const { return hand; @@ -182,33 +112,98 @@ void XRPositionalTracker::set_tracker_hand(const XRPositionalTracker::TrackerHan ERR_FAIL_COND((type != XRServer::TRACKER_CONTROLLER) && (p_hand != XRPositionalTracker::TRACKER_HAND_UNKNOWN)); hand = p_hand; - if (hand == XRPositionalTracker::TRACKER_HAND_LEFT) { - if (!xr_server->is_tracker_id_in_use_for_type(type, 1)) { - tracker_id = 1; - }; - } else if (hand == XRPositionalTracker::TRACKER_HAND_RIGHT) { - if (!xr_server->is_tracker_id_in_use_for_type(type, 2)) { - tracker_id = 2; - }; - }; }; }; -Transform3D XRPositionalTracker::get_transform(bool p_adjust_by_reference_frame) const { - Transform3D new_transform; +bool XRPositionalTracker::has_pose(const StringName &p_action_name) const { + return poses.has(p_action_name); +} - new_transform.basis = get_orientation(); - new_transform.origin = get_position(); +Ref<XRPose> XRPositionalTracker::get_pose(const StringName &p_action_name) const { + Ref<XRPose> pose; - if (p_adjust_by_reference_frame) { - XRServer *xr_server = XRServer::get_singleton(); - ERR_FAIL_NULL_V(xr_server, new_transform); + if (poses.has(p_action_name)) { + pose = poses[p_action_name]; + } - new_transform = xr_server->get_reference_frame() * new_transform; - }; + return pose; +} - return new_transform; -}; +void XRPositionalTracker::invalidate_pose(const StringName &p_action_name) { + // only update this if we were tracking this pose + if (poses.has(p_action_name)) { + // We just set tracking data as invalid, we leave our current transform and velocity data as is so controllers don't suddenly jump to origin. + poses[p_action_name]->set_has_tracking_data(false); + } +} + +void XRPositionalTracker::set_pose(const StringName &p_action_name, const Transform3D &p_transform, const Vector3 &p_linear_velocity, const Vector3 &p_angular_velocity) { + Ref<XRPose> new_pose; + + new_pose.instantiate(); + new_pose->set_name(p_action_name); + new_pose->set_has_tracking_data(true); + new_pose->set_transform(p_transform); + new_pose->set_linear_velocity(p_linear_velocity); + new_pose->set_angular_velocity(p_angular_velocity); + + poses[p_action_name] = new_pose; + emit_signal("pose_changed", new_pose); + + // TODO discuss whether we also want to create and emit an InputEventXRPose event +} + +Variant XRPositionalTracker::get_input(const StringName &p_action_name) const { + if (inputs.has(p_action_name)) { + return inputs[p_action_name]; + } else { + return Variant(); + } +} + +void XRPositionalTracker::set_input(const StringName &p_action_name, const Variant &p_value) { + bool changed = false; + + // XR inputs + + if (inputs.has(p_action_name)) { + changed = inputs[p_action_name] != p_value; + } else { + changed = true; + } + + if (changed) { + // store the new value + inputs[p_action_name] = p_value; + + // emit signals to let the rest of the world know + switch (p_value.get_type()) { + case Variant::BOOL: { + bool pressed = p_value; + if (pressed) { + emit_signal("button_pressed", p_action_name); + } else { + emit_signal("button_released", p_action_name); + } + + // TODO discuss whether we also want to create and emit an InputEventXRButton event + } break; + case Variant::FLOAT: { + emit_signal("input_value_changed", p_action_name, p_value); + + // TODO discuss whether we also want to create and emit an InputEventXRValue event + } break; + case Variant::VECTOR2: { + emit_signal("input_axis_changed", p_action_name, p_value); + + // TODO discuss whether we also want to create and emit an InputEventXRAxis event + } break; + default: { + // ??? + } break; + } + } +} real_t XRPositionalTracker::get_rumble() const { return rumble; @@ -225,10 +220,6 @@ void XRPositionalTracker::set_rumble(real_t p_rumble) { XRPositionalTracker::XRPositionalTracker() { type = XRServer::TRACKER_UNKNOWN; name = "Unknown"; - joy_id = -1; - tracker_id = 0; - tracking_orientation = false; - tracking_position = false; hand = TRACKER_HAND_UNKNOWN; rumble = 0.0; }; diff --git a/servers/xr/xr_positional_tracker.h b/servers/xr/xr_positional_tracker.h index 5577582929..69eb105b5a 100644 --- a/servers/xr/xr_positional_tracker.h +++ b/servers/xr/xr_positional_tracker.h @@ -33,6 +33,7 @@ #include "core/os/thread_safe.h" #include "scene/resources/mesh.h" +#include "servers/xr/xr_pose.h" #include "servers/xr_server.h" /** @@ -57,14 +58,14 @@ public: private: XRServer::TrackerType type; // type of tracker StringName name; // (unique) name of the tracker - int tracker_id; // tracker index id that is unique per type + String description; // description of the tracker, this is interface dependent, for OpenXR this will be the interaction profile bound for to the tracker + TrackerHand hand; // if known, the hand this tracker is held in + + Map<StringName, Ref<XRPose>> poses; + Map<StringName, Variant> inputs; + int joy_id; // if we also have a related joystick entity, the id of the joystick - bool tracking_orientation; // do we track orientation? - Basis orientation; // our orientation - bool tracking_position; // do we track position? - Vector3 rw_position; // our position "in the real world, so without world_scale applied" Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker - TrackerHand hand; // if known, the hand this tracker is held in real_t rumble; // rumble strength, 0.0 is off, 1.0 is maximum, note that we only record here, xr_interface is responsible for execution protected: @@ -73,27 +74,24 @@ protected: public: void set_tracker_type(XRServer::TrackerType p_type); XRServer::TrackerType get_tracker_type() const; - void set_tracker_name(const String &p_name); + void set_tracker_name(const StringName &p_name); StringName get_tracker_name() const; - int get_tracker_id() const; - void set_joy_id(int p_joy_id); - int get_joy_id() const; - bool is_tracking_orientation() const; - void set_orientation(const Basis &p_orientation); - Basis get_orientation() const; - bool is_tracking_position() const; - void set_position(const Vector3 &p_position); // set position with world_scale applied - Vector3 get_position() const; // get position with world_scale applied - void set_rw_position(const Vector3 &p_rw_position); - Vector3 get_rw_position() const; + void set_tracker_desc(const String &p_desc); + String get_tracker_desc() const; XRPositionalTracker::TrackerHand get_tracker_hand() const; void set_tracker_hand(const XRPositionalTracker::TrackerHand p_hand); + + bool has_pose(const StringName &p_action_name) const; + Ref<XRPose> get_pose(const StringName &p_action_name) const; + void invalidate_pose(const StringName &p_action_name); + void set_pose(const StringName &p_action_name, const Transform3D &p_transform, const Vector3 &p_linear_velocity, const Vector3 &p_angular_velocity); + + Variant get_input(const StringName &p_action_name) const; + void set_input(const StringName &p_action_name, const Variant &p_value); + + // TODO replace by new implementation real_t get_rumble() const; void set_rumble(real_t p_rumble); - void set_mesh(const Ref<Mesh> &p_mesh); - Ref<Mesh> get_mesh() const; - - Transform3D get_transform(bool p_adjust_by_reference_frame) const; XRPositionalTracker(); ~XRPositionalTracker() {} diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index c18a9f8b4e..959288497d 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -41,7 +41,7 @@ XRServer *XRServer::get_singleton() { void XRServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_world_scale"), &XRServer::get_world_scale); - ClassDB::bind_method(D_METHOD("set_world_scale"), &XRServer::set_world_scale); + ClassDB::bind_method(D_METHOD("set_world_scale", "scale"), &XRServer::set_world_scale); ClassDB::bind_method(D_METHOD("get_reference_frame"), &XRServer::get_reference_frame); ClassDB::bind_method(D_METHOD("center_on_hmd", "rotation_mode", "keep_height"), &XRServer::center_on_hmd); ClassDB::bind_method(D_METHOD("get_hmd_transform"), &XRServer::get_hmd_transform); @@ -54,10 +54,11 @@ void XRServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_interface", "idx"), &XRServer::get_interface); ClassDB::bind_method(D_METHOD("get_interfaces"), &XRServer::get_interfaces); ClassDB::bind_method(D_METHOD("find_interface", "name"), &XRServer::find_interface); - ClassDB::bind_method(D_METHOD("get_tracker_count"), &XRServer::get_tracker_count); - ClassDB::bind_method(D_METHOD("get_tracker", "idx"), &XRServer::get_tracker); + ClassDB::bind_method(D_METHOD("add_tracker", "tracker"), &XRServer::add_tracker); ClassDB::bind_method(D_METHOD("remove_tracker", "tracker"), &XRServer::remove_tracker); + ClassDB::bind_method(D_METHOD("get_trackers", "tracker_types"), &XRServer::get_trackers); + ClassDB::bind_method(D_METHOD("get_tracker", "tracker_name"), &XRServer::get_tracker); ClassDB::bind_method(D_METHOD("get_primary_interface"), &XRServer::get_primary_interface); ClassDB::bind_method(D_METHOD("set_primary_interface", "interface"), &XRServer::set_primary_interface); @@ -68,6 +69,7 @@ void XRServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_last_commit_usec"), &XRServer::get_last_commit_usec); ClassDB::bind_method(D_METHOD("get_last_frame_usec"), &XRServer::get_last_frame_usec); + BIND_ENUM_CONSTANT(TRACKER_HEAD); BIND_ENUM_CONSTANT(TRACKER_CONTROLLER); BIND_ENUM_CONSTANT(TRACKER_BASESTATION); BIND_ENUM_CONSTANT(TRACKER_ANCHOR); @@ -82,15 +84,16 @@ void XRServer::_bind_methods() { ADD_SIGNAL(MethodInfo("interface_added", PropertyInfo(Variant::STRING_NAME, "interface_name"))); ADD_SIGNAL(MethodInfo("interface_removed", PropertyInfo(Variant::STRING_NAME, "interface_name"))); - ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id"))); - ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"), PropertyInfo(Variant::INT, "id"))); + ADD_SIGNAL(MethodInfo("tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); + ADD_SIGNAL(MethodInfo("tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); + ADD_SIGNAL(MethodInfo("tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::INT, "type"))); }; -real_t XRServer::get_world_scale() const { +double XRServer::get_world_scale() const { return world_scale; }; -void XRServer::set_world_scale(real_t p_world_scale) { +void XRServer::set_world_scale(double p_world_scale) { if (p_world_scale < 0.01) { p_world_scale = 0.01; } else if (p_world_scale > 1000.0) { @@ -113,35 +116,43 @@ Transform3D XRServer::get_reference_frame() const { }; void XRServer::center_on_hmd(RotationMode p_rotation_mode, bool p_keep_height) { - if (primary_interface != nullptr) { - // clear our current reference frame or we'll end up double adjusting it + if (primary_interface == nullptr) { + return; + } + + if (primary_interface->get_play_area_mode() == XRInterface::XR_PLAY_AREA_STAGE) { + // center_on_hmd is not available in this mode reference_frame = Transform3D(); + return; + } - // requesting our EYE_MONO transform should return our current HMD position - Transform3D new_reference_frame = primary_interface->get_camera_transform(); + // clear our current reference frame or we'll end up double adjusting it + reference_frame = Transform3D(); - // remove our tilt - if (p_rotation_mode == 1) { - // take the Y out of our Z - new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized()); + // requesting our EYE_MONO transform should return our current HMD position + Transform3D new_reference_frame = primary_interface->get_camera_transform(); - // Y is straight up - new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0)); + // remove our tilt + if (p_rotation_mode == 1) { + // take the Y out of our Z + new_reference_frame.basis.set_axis(2, Vector3(new_reference_frame.basis.elements[0][2], 0.0, new_reference_frame.basis.elements[2][2]).normalized()); - // and X is our cross reference - new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized()); - } else if (p_rotation_mode == 2) { - // remove our rotation, we're only interesting in centering on position - new_reference_frame.basis = Basis(); - }; + // Y is straight up + new_reference_frame.basis.set_axis(1, Vector3(0.0, 1.0, 0.0)); - // don't negate our height - if (p_keep_height) { - new_reference_frame.origin.y = 0.0; - }; + // and X is our cross reference + new_reference_frame.basis.set_axis(0, new_reference_frame.basis.get_axis(1).cross(new_reference_frame.basis.get_axis(2)).normalized()); + } else if (p_rotation_mode == 2) { + // remove our rotation, we're only interesting in centering on position + new_reference_frame.basis = Basis(); + }; - reference_frame = new_reference_frame.inverse(); + // don't negate our height + if (p_keep_height) { + new_reference_frame.origin.y = 0.0; }; + + reference_frame = new_reference_frame.inverse(); }; Transform3D XRServer::get_hmd_transform() { @@ -182,7 +193,7 @@ void XRServer::remove_interface(const Ref<XRInterface> &p_interface) { print_verbose("XR: Removed interface" + p_interface->get_name()); emit_signal(SNAME("interface_removed"), p_interface->get_name()); - interfaces.remove(idx); + interfaces.remove_at(idx); }; int XRServer::get_interface_count() const { @@ -224,106 +235,121 @@ Array XRServer::get_interfaces() const { return ret; }; -/* - A little extra info on the tracker ids, these are unique per tracker type so we get some consistency in recognising our trackers, specifically controllers. - - The first controller that is turned of will get ID 1, the second will get ID 2, etc. - The magic happens when one of the controllers is turned off, say controller 1 turns off, controller 2 will remain controller 2, controller 3 will remain controller 3. - If controller number 1 is turned on again it again gets ID 1 unless another new controller was turned on since. - - The most likely scenario however is a controller that runs out of battery and another controller being used to replace it. - Because the controllers are often linked to physical objects, say you're holding a shield in controller 1, your left hand, and a gun in controller 2, your right hand, and controller 1 dies: - - using our tracker index would suddenly make the gun disappear and the shield jump into your right hand because controller 2 becomes controller 1. - - using this approach the shield disappears or is no longer tracked, but the gun stays firmly in your right hand because that is still controller 2, further more, if controller 1 is replaced the shield will return. -*/ - -bool XRServer::is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const { - for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { - return true; - }; - }; - - // all good - return false; +Ref<XRInterface> XRServer::get_primary_interface() const { + return primary_interface; }; -int XRServer::get_free_tracker_id_for_type(TrackerType p_tracker_type) { - // We start checking at 1, 0 means that it's not a controller.. - // Note that for controller we reserve: - // - 1 for the left hand controller and - // - 2 for the right hand controller - // so we start at 3 :) - int tracker_id = p_tracker_type == XRServer::TRACKER_CONTROLLER ? 3 : 1; - - while (is_tracker_id_in_use_for_type(p_tracker_type, tracker_id)) { - // try the next one - tracker_id++; - }; +void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) { + if (p_primary_interface.is_null()) { + print_verbose("XR: Clearing primary interface"); + primary_interface.unref(); + } else { + primary_interface = p_primary_interface; - return tracker_id; + print_verbose("XR: Primary interface set to: " + primary_interface->get_name()); + } }; void XRServer::add_tracker(Ref<XRPositionalTracker> p_tracker) { ERR_FAIL_COND(p_tracker.is_null()); - trackers.push_back(p_tracker); - emit_signal(SNAME("tracker_added"), p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); + StringName tracker_name = p_tracker->get_tracker_name(); + if (trackers.has(tracker_name)) { + if (trackers[tracker_name] != p_tracker) { + // We already have a tracker with this name, we're going to replace it + trackers[tracker_name] = p_tracker; + emit_signal(SNAME("tracker_updated"), tracker_name, p_tracker->get_tracker_type()); + } + } else { + trackers[tracker_name] = p_tracker; + emit_signal(SNAME("tracker_added"), tracker_name, p_tracker->get_tracker_type()); + } }; void XRServer::remove_tracker(Ref<XRPositionalTracker> p_tracker) { ERR_FAIL_COND(p_tracker.is_null()); - int idx = -1; - for (int i = 0; i < trackers.size(); i++) { - if (trackers[i] == p_tracker) { - idx = i; - break; - }; - }; - - ERR_FAIL_COND(idx == -1); + StringName tracker_name = p_tracker->get_tracker_name(); + if (trackers.has(tracker_name)) { + // we send the signal right before removing it + emit_signal(SNAME("tracker_removed"), p_tracker->get_tracker_name(), p_tracker->get_tracker_type()); - emit_signal(SNAME("tracker_removed"), p_tracker->get_tracker_name(), p_tracker->get_tracker_type(), p_tracker->get_tracker_id()); - trackers.remove(idx); + // and remove it + trackers.erase(tracker_name); + } }; -int XRServer::get_tracker_count() const { - return trackers.size(); -}; +Dictionary XRServer::get_trackers(int p_tracker_types) { + Dictionary res; -Ref<XRPositionalTracker> XRServer::get_tracker(int p_index) const { - ERR_FAIL_INDEX_V(p_index, trackers.size(), Ref<XRPositionalTracker>()); + for (int i = 0; i < trackers.size(); i++) { + Ref<XRPositionalTracker> tracker = trackers.get_value_at_index(i); + if (tracker.is_valid() && (tracker->get_tracker_type() & p_tracker_types) != 0) { + res[tracker->get_tracker_name()] = tracker; + } + } - return trackers[p_index]; + return res; +} + +Ref<XRPositionalTracker> XRServer::get_tracker(const StringName &p_name) const { + if (trackers.has(p_name)) { + return trackers[p_name]; + } else { + // tracker hasn't been registered yet, which is fine, no need to spam the error log... + return Ref<XRPositionalTracker>(); + } }; -Ref<XRPositionalTracker> XRServer::find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const { - ERR_FAIL_COND_V(p_tracker_id == 0, Ref<XRPositionalTracker>()); +PackedStringArray XRServer::get_suggested_tracker_names() const { + PackedStringArray arr; - for (int i = 0; i < trackers.size(); i++) { - if (trackers[i]->get_tracker_type() == p_tracker_type && trackers[i]->get_tracker_id() == p_tracker_id) { - return trackers[i]; - }; - }; + for (int i = 0; i < interfaces.size(); i++) { + Ref<XRInterface> interface = interfaces[i]; + PackedStringArray interface_arr = interface->get_suggested_tracker_names(); + for (int a = 0; a < interface_arr.size(); a++) { + if (!arr.has(interface_arr[a])) { + arr.push_back(interface_arr[a]); + } + } + } - return Ref<XRPositionalTracker>(); -}; + if (arr.size() == 0) { + // no suggestions from our tracker? include our defaults + arr.push_back(String("head")); + arr.push_back(String("left_hand")); + arr.push_back(String("right_hand")); + } -Ref<XRInterface> XRServer::get_primary_interface() const { - return primary_interface; -}; + return arr; +} -void XRServer::set_primary_interface(const Ref<XRInterface> &p_primary_interface) { - if (p_primary_interface.is_null()) { - print_verbose("XR: Clearing primary interface"); - primary_interface.unref(); - } else { - primary_interface = p_primary_interface; +PackedStringArray XRServer::get_suggested_pose_names(const StringName &p_tracker_name) const { + PackedStringArray arr; - print_verbose("XR: Primary interface set to: " + primary_interface->get_name()); + for (int i = 0; i < interfaces.size(); i++) { + Ref<XRInterface> interface = interfaces[i]; + PackedStringArray interface_arr = interface->get_suggested_pose_names(p_tracker_name); + for (int a = 0; a < interface_arr.size(); a++) { + if (!arr.has(interface_arr[a])) { + arr.push_back(interface_arr[a]); + } + } } -}; + + if (arr.size() == 0) { + // no suggestions from our tracker? include our defaults + arr.push_back(String("default")); + + if ((p_tracker_name == "left_hand") || (p_tracker_name == "right_hand")) { + arr.push_back(String("aim")); + arr.push_back(String("grip")); + arr.push_back(String("skeleton")); + } + } + + return arr; +} uint64_t XRServer::get_last_process_usec() { return last_process_usec; @@ -370,11 +396,12 @@ XRServer::~XRServer() { primary_interface.unref(); while (interfaces.size() > 0) { - interfaces.remove(0); + interfaces.remove_at(0); } + // TODO pretty sure there is a clear function or something... while (trackers.size() > 0) { - trackers.remove(0); + trackers.erase(trackers.get_key_at_index(0)); } singleton = nullptr; diff --git a/servers/xr_server.h b/servers/xr_server.h index af183e175d..48d73cac9a 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -60,9 +60,10 @@ class XRServer : public Object { public: enum TrackerType { - TRACKER_CONTROLLER = 0x01, /* tracks a controller */ - TRACKER_BASESTATION = 0x02, /* tracks location of a base station */ - TRACKER_ANCHOR = 0x04, /* tracks an anchor point, used in AR to track a real live location */ + TRACKER_HEAD = 0x01, /* tracks the position of the players head (or in case of handheld AR, location of the phone) */ + TRACKER_CONTROLLER = 0x02, /* tracks a controller */ + TRACKER_BASESTATION = 0x04, /* tracks location of a base station */ + TRACKER_ANCHOR = 0x08, /* tracks an anchor point, used in AR to track a real live location */ TRACKER_UNKNOWN = 0x80, /* unknown tracker */ TRACKER_ANY_KNOWN = 0x7f, /* all except unknown */ @@ -77,11 +78,11 @@ public: private: Vector<Ref<XRInterface>> interfaces; - Vector<Ref<XRPositionalTracker>> trackers; + Dictionary trackers; Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ - real_t world_scale; /* scale by which we multiply our tracker positions */ + double world_scale; /* scale by which we multiply our tracker positions */ Transform3D world_origin; /* our world origin point, maps a location in our virtual world to the origin point in our real world tracking volume */ Transform3D reference_frame; /* our reference frame */ @@ -107,8 +108,8 @@ public: I may remove access to this property in GDScript in favour of exposing it on the XROrigin3D node */ - real_t get_world_scale() const; - void set_world_scale(real_t p_world_scale); + double get_world_scale() const; + void set_world_scale(double p_world_scale); /* The world maps the 0,0,0 coordinate of our real world coordinate system for our tracking volume to a location in our @@ -164,13 +165,17 @@ public: Our trackers are objects that expose the orientation and position of physical devices such as controller, anchor points, etc. They are created and managed by our active AR/VR interfaces. */ - bool is_tracker_id_in_use_for_type(TrackerType p_tracker_type, int p_tracker_id) const; - int get_free_tracker_id_for_type(TrackerType p_tracker_type); void add_tracker(Ref<XRPositionalTracker> p_tracker); void remove_tracker(Ref<XRPositionalTracker> p_tracker); - int get_tracker_count() const; - Ref<XRPositionalTracker> get_tracker(int p_index) const; - Ref<XRPositionalTracker> find_by_type_and_id(TrackerType p_tracker_type, int p_tracker_id) const; + Dictionary get_trackers(int p_tracker_types); + Ref<XRPositionalTracker> get_tracker(const StringName &p_name) const; + + /* + We don't know which trackers and actions will existing during runtime but we can request suggested names from our interfaces to help our IDE UI. + */ + PackedStringArray get_suggested_tracker_names() const; + PackedStringArray get_suggested_pose_names(const StringName &p_tracker_name) const; + // Q: Should we add get_suggested_input_names and get_suggested_haptic_names even though we don't use them for the IDE? uint64_t get_last_process_usec(); uint64_t get_last_commit_usec(); |