diff options
Diffstat (limited to 'servers')
101 files changed, 2892 insertions, 577 deletions
diff --git a/servers/SCsub b/servers/SCsub index 788a368a4f..736bed68ec 100644 --- a/servers/SCsub +++ b/servers/SCsub @@ -3,19 +3,36 @@ Import("env") env.servers_sources = [] -env.add_source_files(env.servers_sources, "*.cpp") -SConscript("xr/SCsub") -SConscript("camera/SCsub") -SConscript("physics_3d/SCsub") -SConscript("physics_2d/SCsub") -SConscript("rendering/SCsub") +env.add_source_files(env.servers_sources, "audio_server.cpp") +env.add_source_files(env.servers_sources, "camera_server.cpp") +env.add_source_files(env.servers_sources, "display_server.cpp") +env.add_source_files(env.servers_sources, "navigation_server_2d.cpp") +env.add_source_files(env.servers_sources, "navigation_server_3d.cpp") +env.add_source_files(env.servers_sources, "physics_server_2d.cpp") +env.add_source_files(env.servers_sources, "physics_server_2d_wrap_mt.cpp") +env.add_source_files(env.servers_sources, "register_server_types.cpp") +env.add_source_files(env.servers_sources, "rendering_server.cpp") +env.add_source_files(env.servers_sources, "text_server.cpp") + SConscript("audio/SCsub") -SConscript("text/SCsub") +SConscript("camera/SCsub") SConscript("debugger/SCsub") +SConscript("display/SCsub") SConscript("extensions/SCsub") SConscript("movie_writer/SCsub") SConscript("navigation/SCsub") +SConscript("rendering/SCsub") +SConscript("text/SCsub") + +SConscript("physics_2d/SCsub") + +if not env["disable_3d"]: + SConscript("physics_3d/SCsub") + env.add_source_files(env.servers_sources, "physics_server_3d.cpp") + env.add_source_files(env.servers_sources, "physics_server_3d_wrap_mt.cpp") + SConscript("xr/SCsub") + env.add_source_files(env.servers_sources, "xr_server.cpp") lib = env.add_library("servers", env.servers_sources) diff --git a/servers/audio/effects/audio_effect_hard_limiter.cpp b/servers/audio/effects/audio_effect_hard_limiter.cpp new file mode 100644 index 0000000000..e717557af2 --- /dev/null +++ b/servers/audio/effects/audio_effect_hard_limiter.cpp @@ -0,0 +1,161 @@ +/**************************************************************************/ +/* audio_effect_hard_limiter.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "audio_effect_hard_limiter.h" + +#include "servers/audio_server.h" + +void AudioEffectHardLimiterInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) { + float sample_rate = AudioServer::get_singleton()->get_mix_rate(); + + float ceiling = Math::db_to_linear(base->ceiling); + float release = base->release; + float attack = base->attack; + float pre_gain = Math::db_to_linear(base->pre_gain); + + for (int i = 0; i < p_frame_count; i++) { + float sample_left = p_src_frames[i].left; + float sample_right = p_src_frames[i].right; + + sample_left *= pre_gain; + sample_right *= pre_gain; + + float largest_sample = MAX(ABS(sample_left), ABS(sample_right)); + + release_factor = MAX(0.0, release_factor - 1.0 / sample_rate); + release_factor = MIN(release_factor, release); + + if (release_factor > 0.0) { + gain = Math::lerp(gain_target, 1.0f, 1.0f - release_factor / release); + } + + if (largest_sample * gain > ceiling) { + gain_target = ceiling / largest_sample; + release_factor = release; + attack_factor = attack; + } + + // Lerp gain over attack time to avoid distortion. + attack_factor = MAX(0.0f, attack_factor - 1.0f / sample_rate); + if (attack_factor > 0.0) { + gain = Math::lerp(gain_target, gain, 1.0f - attack_factor / attack); + } + + int bucket_id = gain_bucket_cursor / gain_bucket_size; + + // If first item within the current bucket, reset the bucket. + if (gain_bucket_cursor % gain_bucket_size == 0) { + gain_buckets[bucket_id] = 1.0f; + } + + gain_buckets[bucket_id] = MIN(gain_buckets[bucket_id], gain); + + gain_bucket_cursor = (gain_bucket_cursor + 1) % gain_samples_to_store; + + for (int j = 0; j < (int)gain_buckets.size(); j++) { + gain = MIN(gain, gain_buckets[j]); + } + + // Introduce latency by grabbing the AudioFrame stored previously, + // then overwrite it with current audioframe, then update circular + // buffer cursor. + float dst_buffer_left = sample_buffer_left[sample_cursor]; + float dst_buffer_right = sample_buffer_right[sample_cursor]; + + sample_buffer_left[sample_cursor] = sample_left; + sample_buffer_right[sample_cursor] = sample_right; + + sample_cursor = (sample_cursor + 1) % sample_buffer_left.size(); + + p_dst_frames[i].left = dst_buffer_left * gain; + p_dst_frames[i].right = dst_buffer_right * gain; + } +} + +Ref<AudioEffectInstance> AudioEffectHardLimiter::instantiate() { + Ref<AudioEffectHardLimiterInstance> ins; + ins.instantiate(); + ins->base = Ref<AudioEffectHardLimiter>(this); + + float mix_rate = AudioServer::get_singleton()->get_mix_rate(); + + for (int i = 0; i < (int)Math::ceil(mix_rate * attack) + 1; i++) { + ins->sample_buffer_left.push_back(0.0f); + ins->sample_buffer_right.push_back(0.0f); + } + + ins->gain_samples_to_store = (int)Math::ceil(mix_rate * (attack + sustain) + 1); + ins->gain_bucket_size = (int)(mix_rate * attack); + + for (int i = 0; i < ins->gain_samples_to_store; i += ins->gain_bucket_size) { + ins->gain_buckets.push_back(1.0f); + } + + return ins; +} + +void AudioEffectHardLimiter::set_ceiling_db(float p_ceiling) { + ceiling = p_ceiling; +} + +float AudioEffectHardLimiter::get_ceiling_db() const { + return ceiling; +} + +float AudioEffectHardLimiter::get_pre_gain_db() const { + return pre_gain; +} + +void AudioEffectHardLimiter::set_pre_gain_db(const float p_pre_gain) { + pre_gain = p_pre_gain; +} + +float AudioEffectHardLimiter::get_release() const { + return release; +} + +void AudioEffectHardLimiter::set_release(const float p_release) { + release = p_release; +} + +void AudioEffectHardLimiter::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_ceiling_db", "ceiling"), &AudioEffectHardLimiter::set_ceiling_db); + ClassDB::bind_method(D_METHOD("get_ceiling_db"), &AudioEffectHardLimiter::get_ceiling_db); + + ClassDB::bind_method(D_METHOD("set_pre_gain_db", "p_pre_gain"), &AudioEffectHardLimiter::set_pre_gain_db); + ClassDB::bind_method(D_METHOD("get_pre_gain_db"), &AudioEffectHardLimiter::get_pre_gain_db); + + ClassDB::bind_method(D_METHOD("set_release", "p_release"), &AudioEffectHardLimiter::set_release); + ClassDB::bind_method(D_METHOD("get_release"), &AudioEffectHardLimiter::get_release); + + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "pre_gain_db", PROPERTY_HINT_RANGE, "-24,24,0.01,suffix:dB"), "set_pre_gain_db", "get_pre_gain_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "ceiling_db", PROPERTY_HINT_RANGE, "-24,0.0,0.01,suffix:dB"), "set_ceiling_db", "get_ceiling_db"); + ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "release", PROPERTY_HINT_RANGE, "0.01,3,0.01"), "set_release", "get_release"); +} diff --git a/servers/audio/effects/audio_effect_hard_limiter.h b/servers/audio/effects/audio_effect_hard_limiter.h new file mode 100644 index 0000000000..7e28480797 --- /dev/null +++ b/servers/audio/effects/audio_effect_hard_limiter.h @@ -0,0 +1,89 @@ +/**************************************************************************/ +/* audio_effect_hard_limiter.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 AUDIO_EFFECT_HARD_LIMITER_H +#define AUDIO_EFFECT_HARD_LIMITER_H + +#include "servers/audio/audio_effect.h" + +class AudioEffectHardLimiter; + +class AudioEffectHardLimiterInstance : public AudioEffectInstance { + GDCLASS(AudioEffectHardLimiterInstance, AudioEffectInstance); + friend class AudioEffectHardLimiter; + Ref<AudioEffectHardLimiter> base; + +private: + int sample_cursor = 0; + + float release_factor = 0; + float attack_factor = 0; + float gain = 1; + float gain_target = 1; + + LocalVector<float> sample_buffer_left; + LocalVector<float> sample_buffer_right; + + int gain_samples_to_store = 0; + int gain_bucket_cursor = 0; + int gain_bucket_size = 0; + LocalVector<float> gain_buckets; + +public: + virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) override; +}; + +class AudioEffectHardLimiter : public AudioEffect { + GDCLASS(AudioEffectHardLimiter, AudioEffect); + + friend class AudioEffectHardLimiterInstance; + float pre_gain = 0.0f; + float ceiling = -0.3f; + float sustain = 0.02f; + float release = 0.1f; + const float attack = 0.002; + +protected: + static void _bind_methods(); + +public: + void set_ceiling_db(float p_ceiling); + float get_ceiling_db() const; + + void set_release(float p_release); + float get_release() const; + + void set_pre_gain_db(float p_pre_gain); + float get_pre_gain_db() const; + + Ref<AudioEffectInstance> instantiate() override; +}; + +#endif // AUDIO_EFFECT_HARD_LIMITER_H diff --git a/servers/audio/effects/audio_effect_pitch_shift.cpp b/servers/audio/effects/audio_effect_pitch_shift.cpp index ddb17e050a..beca503904 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.cpp +++ b/servers/audio/effects/audio_effect_pitch_shift.cpp @@ -87,10 +87,8 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff double magn, phase, tmp, window, real, imag; double freqPerBin, expct; long i,k, qpd, index, inFifoLatency, stepSize, fftFrameSize2; - unsigned long fftFrameBufferSize; /* set up some handy variables */ - fftFrameBufferSize = (unsigned long)fftFrameSize*sizeof(float); fftFrameSize2 = fftFrameSize/2; stepSize = fftFrameSize/osamp; freqPerBin = sampleRate/(double)fftFrameSize; @@ -162,8 +160,8 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff /* ***************** PROCESSING ******************* */ /* this does the actual pitch shifting */ - memset(gSynMagn, 0, fftFrameBufferSize); - memset(gSynFreq, 0, fftFrameBufferSize); + memset(gSynMagn, 0, fftFrameSize*sizeof(float)); + memset(gSynFreq, 0, fftFrameSize*sizeof(float)); for (k = 0; k <= fftFrameSize2; k++) { index = k*pitchShift; if (index <= fftFrameSize2) { @@ -216,7 +214,7 @@ void SMBPitchShift::PitchShift(float pitchShift, long numSampsToProcess, long ff } /* shift accumulator */ - memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameBufferSize); + memmove(gOutputAccum, gOutputAccum+stepSize, fftFrameSize*sizeof(float)); /* move input FIFO */ for (k = 0; k < inFifoLatency; k++) { gInFIFO[k] = gInFIFO[k+stepSize]; @@ -358,12 +356,3 @@ void AudioEffectPitchShift::_bind_methods() { BIND_ENUM_CONSTANT(FFT_SIZE_4096); BIND_ENUM_CONSTANT(FFT_SIZE_MAX); } - -AudioEffectPitchShift::AudioEffectPitchShift() { - pitch_scale = 1.0; - oversampling = 4; - fft_size = FFT_SIZE_2048; - wet = 0.0; - dry = 0.0; - filter = false; -} diff --git a/servers/audio/effects/audio_effect_pitch_shift.h b/servers/audio/effects/audio_effect_pitch_shift.h index f372cc2124..949ce96057 100644 --- a/servers/audio/effects/audio_effect_pitch_shift.h +++ b/servers/audio/effects/audio_effect_pitch_shift.h @@ -38,34 +38,22 @@ class SMBPitchShift { MAX_FRAME_LENGTH = 8192 }; - float gInFIFO[MAX_FRAME_LENGTH]; - float gOutFIFO[MAX_FRAME_LENGTH]; - float gFFTworksp[2 * MAX_FRAME_LENGTH]; - float gLastPhase[MAX_FRAME_LENGTH / 2 + 1]; - float gSumPhase[MAX_FRAME_LENGTH / 2 + 1]; - float gOutputAccum[2 * MAX_FRAME_LENGTH]; - float gAnaFreq[MAX_FRAME_LENGTH]; - float gAnaMagn[MAX_FRAME_LENGTH]; - float gSynFreq[MAX_FRAME_LENGTH]; - float gSynMagn[MAX_FRAME_LENGTH]; - long gRover; + float gInFIFO[MAX_FRAME_LENGTH] = {}; + float gOutFIFO[MAX_FRAME_LENGTH] = {}; + float gFFTworksp[2 * MAX_FRAME_LENGTH] = {}; + float gLastPhase[MAX_FRAME_LENGTH / 2 + 1] = {}; + float gSumPhase[MAX_FRAME_LENGTH / 2 + 1] = {}; + float gOutputAccum[2 * MAX_FRAME_LENGTH] = {}; + float gAnaFreq[MAX_FRAME_LENGTH] = {}; + float gAnaMagn[MAX_FRAME_LENGTH] = {}; + float gSynFreq[MAX_FRAME_LENGTH] = {}; + float gSynMagn[MAX_FRAME_LENGTH] = {}; + long gRover = 0; void smbFft(float *fftBuffer, long fftFrameSize, long sign); public: void PitchShift(float pitchShift, long numSampsToProcess, long fftFrameSize, long osamp, float sampleRate, float *indata, float *outdata, int stride); - - SMBPitchShift() { - gRover = 0; - memset(gInFIFO, 0, MAX_FRAME_LENGTH * sizeof(float)); - memset(gOutFIFO, 0, MAX_FRAME_LENGTH * sizeof(float)); - memset(gFFTworksp, 0, 2 * MAX_FRAME_LENGTH * sizeof(float)); - memset(gLastPhase, 0, (MAX_FRAME_LENGTH / 2 + 1) * sizeof(float)); - memset(gSumPhase, 0, (MAX_FRAME_LENGTH / 2 + 1) * sizeof(float)); - memset(gOutputAccum, 0, 2 * MAX_FRAME_LENGTH * sizeof(float)); - memset(gAnaFreq, 0, MAX_FRAME_LENGTH * sizeof(float)); - memset(gAnaMagn, 0, MAX_FRAME_LENGTH * sizeof(float)); - } }; class AudioEffectPitchShift; @@ -75,7 +63,7 @@ class AudioEffectPitchShiftInstance : public AudioEffectInstance { friend class AudioEffectPitchShift; Ref<AudioEffectPitchShift> base; - int fft_size; + int fft_size = 0; SMBPitchShift shift_l; SMBPitchShift shift_r; @@ -98,12 +86,12 @@ public: FFT_SIZE_MAX }; - float pitch_scale; - int oversampling; - FFTSize fft_size; - float wet; - float dry; - bool filter; + float pitch_scale = 1.0; + int oversampling = 4; + FFTSize fft_size = FFT_SIZE_2048; + float wet = 0.0; + float dry = 0.0; + bool filter = false; protected: static void _bind_methods(); @@ -119,8 +107,6 @@ public: void set_fft_size(FFTSize); FFTSize get_fft_size() const; - - AudioEffectPitchShift(); }; VARIANT_ENUM_CAST(AudioEffectPitchShift::FFTSize); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index 69a66a7d62..820e0bbeb6 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -1692,6 +1692,19 @@ void AudioServer::set_enable_tagging_used_audio_streams(bool p_enable) { tag_used_audio_streams = p_enable; } +#ifdef TOOLS_ENABLED +void AudioServer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { + const String pf = p_function; + if ((p_idx == 0 && pf == "get_bus_index") || (p_idx == 1 && pf == "set_bus_send")) { + for (const AudioServer::Bus *E : buses) { + r_options->push_back(String(E->name).quote()); + } + } + + Object::get_argument_options(p_function, p_idx, r_options); +} +#endif + void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bus_count", "amount"), &AudioServer::set_bus_count); ClassDB::bind_method(D_METHOD("get_bus_count"), &AudioServer::get_bus_count); diff --git a/servers/audio_server.h b/servers/audio_server.h index a7b764d1a5..7dd81beabe 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -436,6 +436,10 @@ public: void set_enable_tagging_used_audio_streams(bool p_enable); +#ifdef TOOLS_ENABLED + virtual void get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const override; +#endif + AudioServer(); virtual ~AudioServer(); }; diff --git a/servers/camera_server.h b/servers/camera_server.h index 4e0b75fbf6..e9bcd771d2 100644 --- a/servers/camera_server.h +++ b/servers/camera_server.h @@ -71,7 +71,7 @@ protected: static void _bind_methods(); - template <class T> + template <typename T> static CameraServer *_create_builtin() { return memnew(T); } @@ -79,7 +79,7 @@ protected: public: static CameraServer *get_singleton(); - template <class T> + template <typename T> static void make_default() { create_func = _create_builtin<T>; } diff --git a/servers/display/SCsub b/servers/display/SCsub new file mode 100644 index 0000000000..86681f9c74 --- /dev/null +++ b/servers/display/SCsub @@ -0,0 +1,5 @@ +#!/usr/bin/env python + +Import("env") + +env.add_source_files(env.servers_sources, "*.cpp") diff --git a/servers/display/native_menu.cpp b/servers/display/native_menu.cpp new file mode 100644 index 0000000000..ca46560c7c --- /dev/null +++ b/servers/display/native_menu.cpp @@ -0,0 +1,444 @@ +/**************************************************************************/ +/* native_menu.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 "native_menu.h" + +#include "scene/resources/image_texture.h" + +NativeMenu *NativeMenu::singleton = nullptr; + +void NativeMenu::_bind_methods() { + ClassDB::bind_method(D_METHOD("has_feature", "feature"), &NativeMenu::has_feature); + + ClassDB::bind_method(D_METHOD("has_system_menu", "menu_id"), &NativeMenu::has_system_menu); + ClassDB::bind_method(D_METHOD("get_system_menu", "menu_id"), &NativeMenu::get_system_menu); + ClassDB::bind_method(D_METHOD("get_system_menu_name", "menu_id"), &NativeMenu::get_system_menu_name); + + ClassDB::bind_method(D_METHOD("create_menu"), &NativeMenu::create_menu); + ClassDB::bind_method(D_METHOD("has_menu", "rid"), &NativeMenu::has_menu); + ClassDB::bind_method(D_METHOD("free_menu", "rid"), &NativeMenu::free_menu); + + ClassDB::bind_method(D_METHOD("get_size", "rid"), &NativeMenu::get_size); + ClassDB::bind_method(D_METHOD("popup", "rid", "position"), &NativeMenu::popup); + + ClassDB::bind_method(D_METHOD("set_interface_direction", "rid", "is_rtl"), &NativeMenu::set_interface_direction); + ClassDB::bind_method(D_METHOD("set_popup_open_callback", "rid", "callback"), &NativeMenu::set_popup_open_callback); + ClassDB::bind_method(D_METHOD("get_popup_open_callback", "rid"), &NativeMenu::get_popup_open_callback); + ClassDB::bind_method(D_METHOD("set_popup_close_callback", "rid", "callback"), &NativeMenu::set_popup_close_callback); + ClassDB::bind_method(D_METHOD("get_popup_close_callback", "rid"), &NativeMenu::get_popup_close_callback); + ClassDB::bind_method(D_METHOD("set_minimum_width", "rid", "width"), &NativeMenu::set_minimum_width); + ClassDB::bind_method(D_METHOD("get_minimum_width", "rid"), &NativeMenu::get_minimum_width); + + ClassDB::bind_method(D_METHOD("add_submenu_item", "rid", "label", "submenu_rid", "tag", "index"), &NativeMenu::add_submenu_item, DEFVAL(Variant()), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_item", "rid", "label", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_check_item", "rid", "label", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_icon_item", "rid", "icon", "label", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_icon_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_icon_check_item", "rid", "icon", "label", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_icon_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_radio_check_item", "rid", "label", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_radio_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_icon_radio_check_item", "rid", "icon", "label", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_icon_radio_check_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_multistate_item", "rid", "label", "max_states", "default_state", "callback", "key_callback", "tag", "accelerator", "index"), &NativeMenu::add_multistate_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1)); + ClassDB::bind_method(D_METHOD("add_separator", "rid", "index"), &NativeMenu::add_separator, DEFVAL(-1)); + + ClassDB::bind_method(D_METHOD("find_item_index_with_text", "rid", "text"), &NativeMenu::find_item_index_with_text); + ClassDB::bind_method(D_METHOD("find_item_index_with_tag", "rid", "tag"), &NativeMenu::find_item_index_with_tag); + ClassDB::bind_method(D_METHOD("find_item_index_with_submenu", "rid", "submenu_rid"), &NativeMenu::find_item_index_with_submenu); + + ClassDB::bind_method(D_METHOD("is_item_checked", "rid", "idx"), &NativeMenu::is_item_checked); + ClassDB::bind_method(D_METHOD("is_item_checkable", "rid", "idx"), &NativeMenu::is_item_checkable); + ClassDB::bind_method(D_METHOD("is_item_radio_checkable", "rid", "idx"), &NativeMenu::is_item_radio_checkable); + ClassDB::bind_method(D_METHOD("get_item_callback", "rid", "idx"), &NativeMenu::get_item_callback); + ClassDB::bind_method(D_METHOD("get_item_key_callback", "rid", "idx"), &NativeMenu::get_item_key_callback); + ClassDB::bind_method(D_METHOD("get_item_tag", "rid", "idx"), &NativeMenu::get_item_tag); + ClassDB::bind_method(D_METHOD("get_item_text", "rid", "idx"), &NativeMenu::get_item_text); + ClassDB::bind_method(D_METHOD("get_item_submenu", "rid", "idx"), &NativeMenu::get_item_submenu); + ClassDB::bind_method(D_METHOD("get_item_accelerator", "rid", "idx"), &NativeMenu::get_item_accelerator); + ClassDB::bind_method(D_METHOD("is_item_disabled", "rid", "idx"), &NativeMenu::is_item_disabled); + ClassDB::bind_method(D_METHOD("is_item_hidden", "rid", "idx"), &NativeMenu::is_item_hidden); + ClassDB::bind_method(D_METHOD("get_item_tooltip", "rid", "idx"), &NativeMenu::get_item_tooltip); + ClassDB::bind_method(D_METHOD("get_item_state", "rid", "idx"), &NativeMenu::get_item_state); + ClassDB::bind_method(D_METHOD("get_item_max_states", "rid", "idx"), &NativeMenu::get_item_max_states); + ClassDB::bind_method(D_METHOD("get_item_icon", "rid", "idx"), &NativeMenu::get_item_icon); + ClassDB::bind_method(D_METHOD("get_item_indentation_level", "rid", "idx"), &NativeMenu::get_item_indentation_level); + + ClassDB::bind_method(D_METHOD("set_item_checked", "rid", "idx", "checked"), &NativeMenu::set_item_checked); + ClassDB::bind_method(D_METHOD("set_item_checkable", "rid", "idx", "checkable"), &NativeMenu::set_item_checkable); + ClassDB::bind_method(D_METHOD("set_item_radio_checkable", "rid", "idx", "checkable"), &NativeMenu::set_item_radio_checkable); + ClassDB::bind_method(D_METHOD("set_item_callback", "rid", "idx", "callback"), &NativeMenu::set_item_callback); + ClassDB::bind_method(D_METHOD("set_item_hover_callbacks", "rid", "idx", "callback"), &NativeMenu::set_item_hover_callbacks); + ClassDB::bind_method(D_METHOD("set_item_key_callback", "rid", "idx", "key_callback"), &NativeMenu::set_item_key_callback); + ClassDB::bind_method(D_METHOD("set_item_tag", "rid", "idx", "tag"), &NativeMenu::set_item_tag); + ClassDB::bind_method(D_METHOD("set_item_text", "rid", "idx", "text"), &NativeMenu::set_item_text); + ClassDB::bind_method(D_METHOD("set_item_submenu", "rid", "idx", "submenu_rid"), &NativeMenu::set_item_submenu); + ClassDB::bind_method(D_METHOD("set_item_accelerator", "rid", "idx", "keycode"), &NativeMenu::set_item_accelerator); + ClassDB::bind_method(D_METHOD("set_item_disabled", "rid", "idx", "disabled"), &NativeMenu::set_item_disabled); + ClassDB::bind_method(D_METHOD("set_item_hidden", "rid", "idx", "hidden"), &NativeMenu::set_item_hidden); + ClassDB::bind_method(D_METHOD("set_item_tooltip", "rid", "idx", "tooltip"), &NativeMenu::set_item_tooltip); + ClassDB::bind_method(D_METHOD("set_item_state", "rid", "idx", "state"), &NativeMenu::set_item_state); + ClassDB::bind_method(D_METHOD("set_item_max_states", "rid", "idx", "max_states"), &NativeMenu::set_item_max_states); + ClassDB::bind_method(D_METHOD("set_item_icon", "rid", "idx", "icon"), &NativeMenu::set_item_icon); + ClassDB::bind_method(D_METHOD("set_item_indentation_level", "rid", "idx", "level"), &NativeMenu::set_item_indentation_level); + + ClassDB::bind_method(D_METHOD("get_item_count", "rid"), &NativeMenu::get_item_count); + ClassDB::bind_method(D_METHOD("is_system_menu", "rid"), &NativeMenu::is_system_menu); + + ClassDB::bind_method(D_METHOD("remove_item", "rid", "idx"), &NativeMenu::remove_item); + ClassDB::bind_method(D_METHOD("clear", "rid"), &NativeMenu::clear); + + BIND_ENUM_CONSTANT(FEATURE_GLOBAL_MENU); + BIND_ENUM_CONSTANT(FEATURE_POPUP_MENU); + BIND_ENUM_CONSTANT(FEATURE_OPEN_CLOSE_CALLBACK); + BIND_ENUM_CONSTANT(FEATURE_HOVER_CALLBACK); + BIND_ENUM_CONSTANT(FEATURE_KEY_CALLBACK); + + BIND_ENUM_CONSTANT(INVALID_MENU_ID); + BIND_ENUM_CONSTANT(MAIN_MENU_ID); + BIND_ENUM_CONSTANT(APPLICATION_MENU_ID); + BIND_ENUM_CONSTANT(WINDOW_MENU_ID); + BIND_ENUM_CONSTANT(HELP_MENU_ID); + BIND_ENUM_CONSTANT(DOCK_MENU_ID); +} + +bool NativeMenu::has_feature(Feature p_feature) const { + return false; +} + +bool NativeMenu::has_system_menu(SystemMenus p_menu_id) const { + return false; +} + +RID NativeMenu::get_system_menu(SystemMenus p_menu_id) const { + WARN_PRINT("Global menus are not supported on this platform."); + return RID(); +} + +String NativeMenu::get_system_menu_name(SystemMenus p_menu_id) const { + switch (p_menu_id) { + case MAIN_MENU_ID: + return "Main menu"; + case APPLICATION_MENU_ID: + return "Application menu"; + case WINDOW_MENU_ID: + return "Window menu"; + case HELP_MENU_ID: + return "Help menu"; + case DOCK_MENU_ID: + return "Dock menu"; + default: + return "Invalid"; + } +} + +RID NativeMenu::create_menu() { + WARN_PRINT("Global menus are not supported on this platform."); + return RID(); +} + +bool NativeMenu::has_menu(const RID &p_rid) const { + WARN_PRINT("Global menus are not supported on this platform."); + return false; +} + +void NativeMenu::free_menu(const RID &p_rid) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +Size2 NativeMenu::get_size(const RID &p_rid) const { + WARN_PRINT("Global menus are not supported on this platform."); + return Size2(); +} + +void NativeMenu::popup(const RID &p_rid, const Vector2i &p_position) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_interface_direction(const RID &p_rid, bool p_is_rtl) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_popup_open_callback(const RID &p_rid, const Callable &p_callback) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +Callable NativeMenu::get_popup_open_callback(const RID &p_rid) const { + WARN_PRINT("Global menus are not supported on this platform."); + return Callable(); +} + +void NativeMenu::set_popup_close_callback(const RID &p_rid, const Callable &p_callback) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +Callable NativeMenu::get_popup_close_callback(const RID &p_rid) const { + WARN_PRINT("Global menus are not supported on this platform."); + return Callable(); +} + +void NativeMenu::set_minimum_width(const RID &p_rid, float p_width) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +float NativeMenu::get_minimum_width(const RID &p_rid) const { + WARN_PRINT("Global menus are not supported on this platform."); + return 0.f; +} + +int NativeMenu::add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::add_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::add_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::add_icon_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::add_icon_check_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::add_radio_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::add_icon_radio_check_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::add_multistate_item(const RID &p_rid, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::add_separator(const RID &p_rid, int p_index) { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::find_item_index_with_text(const RID &p_rid, const String &p_text) const { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) const { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::find_item_index_with_submenu(const RID &p_rid, const RID &p_submenu_rid) const { + if (!has_menu(p_rid) || !has_menu(p_submenu_rid)) { + return -1; + } + int count = get_item_count(p_rid); + for (int i = 0; i < count; i++) { + if (p_submenu_rid == get_item_submenu(p_rid, i)) { + return i; + } + } + return -1; +} + +bool NativeMenu::is_item_checked(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return false; +} + +bool NativeMenu::is_item_checkable(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return false; +} + +bool NativeMenu::is_item_radio_checkable(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return false; +} + +Callable NativeMenu::get_item_callback(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return Callable(); +} + +Callable NativeMenu::get_item_key_callback(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return Callable(); +} + +Variant NativeMenu::get_item_tag(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return Variant(); +} + +String NativeMenu::get_item_text(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return String(); +} + +RID NativeMenu::get_item_submenu(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return RID(); +} + +Key NativeMenu::get_item_accelerator(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return Key::NONE; +} + +bool NativeMenu::is_item_disabled(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return false; +} + +bool NativeMenu::is_item_hidden(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return false; +} + +String NativeMenu::get_item_tooltip(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return String(); +} + +int NativeMenu::get_item_state(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +int NativeMenu::get_item_max_states(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return -1; +} + +Ref<Texture2D> NativeMenu::get_item_icon(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return Ref<Texture2D>(); +} + +int NativeMenu::get_item_indentation_level(const RID &p_rid, int p_idx) const { + WARN_PRINT("Global menus are not supported on this platform."); + return 0; +} + +void NativeMenu::set_item_checked(const RID &p_rid, int p_idx, bool p_checked) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_checkable(const RID &p_rid, int p_idx, bool p_checkable) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_radio_checkable(const RID &p_rid, int p_idx, bool p_checkable) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_callback(const RID &p_rid, int p_idx, const Callable &p_callback) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_key_callback(const RID &p_rid, int p_idx, const Callable &p_key_callback) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_hover_callbacks(const RID &p_rid, int p_idx, const Callable &p_callback) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_tag(const RID &p_rid, int p_idx, const Variant &p_tag) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_text(const RID &p_rid, int p_idx, const String &p_text) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_submenu(const RID &p_rid, int p_idx, const RID &p_submenu_rid) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_accelerator(const RID &p_rid, int p_idx, Key p_keycode) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_disabled(const RID &p_rid, int p_idx, bool p_disabled) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_hidden(const RID &p_rid, int p_idx, bool p_hidden) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_tooltip(const RID &p_rid, int p_idx, const String &p_tooltip) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_state(const RID &p_rid, int p_idx, int p_state) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_max_states(const RID &p_rid, int p_idx, int p_max_states) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_icon(const RID &p_rid, int p_idx, const Ref<Texture2D> &p_icon) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::set_item_indentation_level(const RID &p_rid, int p_idx, int p_level) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +int NativeMenu::get_item_count(const RID &p_rid) const { + WARN_PRINT("Global menus are not supported on this platform."); + return 0; +} + +bool NativeMenu::is_system_menu(const RID &p_rid) const { + WARN_PRINT("Global menus are not supported on this platform."); + return false; +} + +void NativeMenu::remove_item(const RID &p_rid, int p_idx) { + WARN_PRINT("Global menus are not supported on this platform."); +} + +void NativeMenu::clear(const RID &p_rid) { + WARN_PRINT("Global menus are not supported on this platform."); +} diff --git a/servers/display/native_menu.h b/servers/display/native_menu.h new file mode 100644 index 0000000000..2bc061a216 --- /dev/null +++ b/servers/display/native_menu.h @@ -0,0 +1,160 @@ +/**************************************************************************/ +/* native_menu.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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 NATIVE_MENU_H +#define NATIVE_MENU_H + +#include "core/input/input.h" +#include "core/io/resource.h" +#include "core/os/os.h" +#include "core/variant/callable.h" + +class Texture2D; + +class NativeMenu : public Object { + GDCLASS(NativeMenu, Object) + + static NativeMenu *singleton; + +protected: + static void _bind_methods(); + +public: + _FORCE_INLINE_ static NativeMenu *get_singleton() { + return singleton; + } + + enum Feature { + FEATURE_GLOBAL_MENU, + FEATURE_POPUP_MENU, + FEATURE_OPEN_CLOSE_CALLBACK, + FEATURE_HOVER_CALLBACK, + FEATURE_KEY_CALLBACK, + }; + + enum SystemMenus { + INVALID_MENU_ID, + MAIN_MENU_ID, + APPLICATION_MENU_ID, + WINDOW_MENU_ID, + HELP_MENU_ID, + DOCK_MENU_ID, + }; + + virtual bool has_feature(Feature p_feature) const; + + virtual bool has_system_menu(SystemMenus p_menu_id) const; + virtual RID get_system_menu(SystemMenus p_menu_id) const; + virtual String get_system_menu_name(SystemMenus p_menu_id) const; + + virtual RID create_menu(); + virtual bool has_menu(const RID &p_rid) const; + virtual void free_menu(const RID &p_rid); + + virtual Size2 get_size(const RID &p_rid) const; + virtual void popup(const RID &p_rid, const Vector2i &p_position); + + virtual void set_interface_direction(const RID &p_rid, bool p_is_rtl); + + virtual void set_popup_open_callback(const RID &p_rid, const Callable &p_callback); + virtual Callable get_popup_open_callback(const RID &p_rid) const; + virtual void set_popup_close_callback(const RID &p_rid, const Callable &p_callback); + virtual Callable get_popup_close_callback(const RID &p_rid) const; + virtual void set_minimum_width(const RID &p_rid, float p_width); + virtual float get_minimum_width(const RID &p_rid) const; + + virtual int add_submenu_item(const RID &p_rid, const String &p_label, const RID &p_submenu_rid, const Variant &p_tag = Variant(), int p_index = -1); + virtual int add_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1); + virtual int add_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1); + virtual int add_icon_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1); + virtual int add_icon_check_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1); + virtual int add_radio_check_item(const RID &p_rid, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1); + virtual int add_icon_radio_check_item(const RID &p_rid, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1); + virtual int add_multistate_item(const RID &p_rid, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback = Callable(), const Callable &p_key_callback = Callable(), const Variant &p_tag = Variant(), Key p_accel = Key::NONE, int p_index = -1); + virtual int add_separator(const RID &p_rid, int p_index = -1); + + virtual int find_item_index_with_text(const RID &p_rid, const String &p_text) const; + virtual int find_item_index_with_tag(const RID &p_rid, const Variant &p_tag) const; + virtual int find_item_index_with_submenu(const RID &p_rid, const RID &p_submenu_rid) const; + + virtual bool is_item_checked(const RID &p_rid, int p_idx) const; + virtual bool is_item_checkable(const RID &p_rid, int p_idx) const; + virtual bool is_item_radio_checkable(const RID &p_rid, int p_idx) const; + virtual Callable get_item_callback(const RID &p_rid, int p_idx) const; + virtual Callable get_item_key_callback(const RID &p_rid, int p_idx) const; + virtual Variant get_item_tag(const RID &p_rid, int p_idx) const; + virtual String get_item_text(const RID &p_rid, int p_idx) const; + virtual RID get_item_submenu(const RID &p_rid, int p_idx) const; + virtual Key get_item_accelerator(const RID &p_rid, int p_idx) const; + virtual bool is_item_disabled(const RID &p_rid, int p_idx) const; + virtual bool is_item_hidden(const RID &p_rid, int p_idx) const; + virtual String get_item_tooltip(const RID &p_rid, int p_idx) const; + virtual int get_item_state(const RID &p_rid, int p_idx) const; + virtual int get_item_max_states(const RID &p_rid, int p_idx) const; + virtual Ref<Texture2D> get_item_icon(const RID &p_rid, int p_idx) const; + virtual int get_item_indentation_level(const RID &p_rid, int p_idx) const; + + virtual void set_item_checked(const RID &p_rid, int p_idx, bool p_checked); + virtual void set_item_checkable(const RID &p_rid, int p_idx, bool p_checkable); + virtual void set_item_radio_checkable(const RID &p_rid, int p_idx, bool p_checkable); + virtual void set_item_callback(const RID &p_rid, int p_idx, const Callable &p_callback); + virtual void set_item_key_callback(const RID &p_rid, int p_idx, const Callable &p_key_callback); + virtual void set_item_hover_callbacks(const RID &p_rid, int p_idx, const Callable &p_callback); + virtual void set_item_tag(const RID &p_rid, int p_idx, const Variant &p_tag); + virtual void set_item_text(const RID &p_rid, int p_idx, const String &p_text); + virtual void set_item_submenu(const RID &p_rid, int p_idx, const RID &p_submenu_rid); + virtual void set_item_accelerator(const RID &p_rid, int p_idx, Key p_keycode); + virtual void set_item_disabled(const RID &p_rid, int p_idx, bool p_disabled); + virtual void set_item_hidden(const RID &p_rid, int p_idx, bool p_hidden); + virtual void set_item_tooltip(const RID &p_rid, int p_idx, const String &p_tooltip); + virtual void set_item_state(const RID &p_rid, int p_idx, int p_state); + virtual void set_item_max_states(const RID &p_rid, int p_idx, int p_max_states); + virtual void set_item_icon(const RID &p_rid, int p_idx, const Ref<Texture2D> &p_icon); + virtual void set_item_indentation_level(const RID &p_rid, int p_idx, int p_level); + + virtual int get_item_count(const RID &p_rid) const; + virtual bool is_system_menu(const RID &p_rid) const; + + virtual void remove_item(const RID &p_rid, int p_idx); + virtual void clear(const RID &p_rid); + + NativeMenu() { + singleton = this; + } + + ~NativeMenu() { + singleton = nullptr; + } +}; + +VARIANT_ENUM_CAST(NativeMenu::Feature); +VARIANT_ENUM_CAST(NativeMenu::SystemMenus); + +#endif // NATIVE_MENU_H diff --git a/servers/display_server.cpp b/servers/display_server.cpp index 6631d44f63..9ceb6909fe 100644 --- a/servers/display_server.cpp +++ b/servers/display_server.cpp @@ -31,6 +31,7 @@ #include "display_server.h" #include "core/input/input.h" +#include "scene/resources/atlas_texture.h" #include "scene/resources/texture.h" #include "servers/display_server_headless.h" @@ -51,231 +52,352 @@ void DisplayServer::help_set_search_callbacks(const Callable &p_search_callback, WARN_PRINT("Native help is not supported by this display server."); } +#ifndef DISABLE_DEPRECATED + +RID DisplayServer::_get_rid_from_name(NativeMenu *p_nmenu, const String &p_menu_root) const { + if (p_menu_root == "_main") { + return p_nmenu->get_system_menu(NativeMenu::MAIN_MENU_ID); + } else if (p_menu_root == "_apple") { + return p_nmenu->get_system_menu(NativeMenu::APPLICATION_MENU_ID); + } else if (p_menu_root == "_dock") { + return p_nmenu->get_system_menu(NativeMenu::DOCK_MENU_ID); + } else if (p_menu_root == "_help") { + return p_nmenu->get_system_menu(NativeMenu::HELP_MENU_ID); + } else if (p_menu_root == "_window") { + return p_nmenu->get_system_menu(NativeMenu::WINDOW_MENU_ID); + } else if (menu_names.has(p_menu_root)) { + return menu_names[p_menu_root]; + } + + RID rid = p_nmenu->create_menu(); + menu_names[p_menu_root] = rid; + return rid; +} + int DisplayServer::global_menu_add_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_item(_get_rid_from_name(nmenu, p_menu_root), p_label, p_callback, p_key_callback, p_tag, p_accel, p_index); } int DisplayServer::global_menu_add_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_check_item(_get_rid_from_name(nmenu, p_menu_root), p_label, p_callback, p_key_callback, p_tag, p_accel, p_index); } int DisplayServer::global_menu_add_icon_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_icon_item(_get_rid_from_name(nmenu, p_menu_root), p_icon, p_label, p_callback, p_key_callback, p_tag, p_accel, p_index); } int DisplayServer::global_menu_add_icon_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_icon_check_item(_get_rid_from_name(nmenu, p_menu_root), p_icon, p_label, p_callback, p_key_callback, p_tag, p_accel, p_index); } int DisplayServer::global_menu_add_radio_check_item(const String &p_menu_root, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_radio_check_item(_get_rid_from_name(nmenu, p_menu_root), p_label, p_callback, p_key_callback, p_tag, p_accel, p_index); } int DisplayServer::global_menu_add_icon_radio_check_item(const String &p_menu_root, const Ref<Texture2D> &p_icon, const String &p_label, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_icon_radio_check_item(_get_rid_from_name(nmenu, p_menu_root), p_icon, p_label, p_callback, p_key_callback, p_tag, p_accel, p_index); } int DisplayServer::global_menu_add_multistate_item(const String &p_menu_root, const String &p_label, int p_max_states, int p_default_state, const Callable &p_callback, const Callable &p_key_callback, const Variant &p_tag, Key p_accel, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_multistate_item(_get_rid_from_name(nmenu, p_menu_root), p_label, p_max_states, p_default_state, p_callback, p_key_callback, p_tag, p_accel, p_index); } -void DisplayServer::global_menu_set_popup_callbacks(const String &p_menu_root, const Callable &p_open_callbacs, const Callable &p_close_callback) { - WARN_PRINT("Global menus not supported by this display server."); +void DisplayServer::global_menu_set_popup_callbacks(const String &p_menu_root, const Callable &p_open_callback, const Callable &p_close_callback) { + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_popup_open_callback(_get_rid_from_name(nmenu, p_menu_root), p_open_callback); + nmenu->set_popup_open_callback(_get_rid_from_name(nmenu, p_menu_root), p_close_callback); } int DisplayServer::global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_submenu_item(_get_rid_from_name(nmenu, p_menu_root), p_label, _get_rid_from_name(nmenu, p_submenu), Variant(), p_index); } int DisplayServer::global_menu_add_separator(const String &p_menu_root, int p_index) { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->add_separator(_get_rid_from_name(nmenu, p_menu_root), p_index); } int DisplayServer::global_menu_get_item_index_from_text(const String &p_menu_root, const String &p_text) const { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->find_item_index_with_text(_get_rid_from_name(nmenu, p_menu_root), p_text); } int DisplayServer::global_menu_get_item_index_from_tag(const String &p_menu_root, const Variant &p_tag) const { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->find_item_index_with_tag(_get_rid_from_name(nmenu, p_menu_root), p_tag); } void DisplayServer::global_menu_set_item_callback(const String &p_menu_root, int p_idx, const Callable &p_callback) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_callback(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_callback); } void DisplayServer::global_menu_set_item_hover_callbacks(const String &p_menu_root, int p_idx, const Callable &p_callback) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_hover_callbacks(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_callback); } void DisplayServer::global_menu_set_item_key_callback(const String &p_menu_root, int p_idx, const Callable &p_key_callback) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_key_callback(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_key_callback); } bool DisplayServer::global_menu_is_item_checked(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return false; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, false); + return nmenu->is_item_checked(_get_rid_from_name(nmenu, p_menu_root), p_idx); } bool DisplayServer::global_menu_is_item_checkable(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return false; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, false); + return nmenu->is_item_checkable(_get_rid_from_name(nmenu, p_menu_root), p_idx); } bool DisplayServer::global_menu_is_item_radio_checkable(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return false; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, false); + return nmenu->is_item_radio_checkable(_get_rid_from_name(nmenu, p_menu_root), p_idx); } Callable DisplayServer::global_menu_get_item_callback(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return Callable(); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, Callable()); + return nmenu->get_item_callback(_get_rid_from_name(nmenu, p_menu_root), p_idx); } Callable DisplayServer::global_menu_get_item_key_callback(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return Callable(); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, Callable()); + return nmenu->get_item_key_callback(_get_rid_from_name(nmenu, p_menu_root), p_idx); } Variant DisplayServer::global_menu_get_item_tag(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return Variant(); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, Variant()); + return nmenu->get_item_tag(_get_rid_from_name(nmenu, p_menu_root), p_idx); } String DisplayServer::global_menu_get_item_text(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return String(); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, String()); + return nmenu->get_item_text(_get_rid_from_name(nmenu, p_menu_root), p_idx); } String DisplayServer::global_menu_get_item_submenu(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, String()); + RID rid = nmenu->get_item_submenu(_get_rid_from_name(nmenu, p_menu_root), p_idx); + if (!nmenu->is_system_menu(rid)) { + for (HashMap<String, RID>::Iterator E = menu_names.begin(); E;) { + if (E->value == rid) { + return E->key; + } + } + } return String(); } Key DisplayServer::global_menu_get_item_accelerator(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return Key::NONE; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, Key::NONE); + return nmenu->get_item_accelerator(_get_rid_from_name(nmenu, p_menu_root), p_idx); } bool DisplayServer::global_menu_is_item_disabled(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return false; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, false); + return nmenu->is_item_disabled(_get_rid_from_name(nmenu, p_menu_root), p_idx); } bool DisplayServer::global_menu_is_item_hidden(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return false; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, false); + return nmenu->is_item_hidden(_get_rid_from_name(nmenu, p_menu_root), p_idx); } String DisplayServer::global_menu_get_item_tooltip(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return String(); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, String()); + return nmenu->get_item_tooltip(_get_rid_from_name(nmenu, p_menu_root), p_idx); } int DisplayServer::global_menu_get_item_state(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->get_item_state(_get_rid_from_name(nmenu, p_menu_root), p_idx); } int DisplayServer::global_menu_get_item_max_states(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return -1; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, -1); + return nmenu->get_item_max_states(_get_rid_from_name(nmenu, p_menu_root), p_idx); } Ref<Texture2D> DisplayServer::global_menu_get_item_icon(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return Ref<Texture2D>(); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, Ref<Texture2D>()); + return nmenu->get_item_icon(_get_rid_from_name(nmenu, p_menu_root), p_idx); } int DisplayServer::global_menu_get_item_indentation_level(const String &p_menu_root, int p_idx) const { - WARN_PRINT("Global menus not supported by this display server."); - return 0; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, 0); + return nmenu->get_item_indentation_level(_get_rid_from_name(nmenu, p_menu_root), p_idx); } void DisplayServer::global_menu_set_item_checked(const String &p_menu_root, int p_idx, bool p_checked) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_checked(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_checked); } void DisplayServer::global_menu_set_item_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_checkable(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_checkable); } void DisplayServer::global_menu_set_item_radio_checkable(const String &p_menu_root, int p_idx, bool p_checkable) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_radio_checkable(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_checkable); } void DisplayServer::global_menu_set_item_tag(const String &p_menu_root, int p_idx, const Variant &p_tag) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_tag(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_tag); } void DisplayServer::global_menu_set_item_text(const String &p_menu_root, int p_idx, const String &p_text) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_text(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_text); } void DisplayServer::global_menu_set_item_submenu(const String &p_menu_root, int p_idx, const String &p_submenu) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_submenu(_get_rid_from_name(nmenu, p_menu_root), p_idx, _get_rid_from_name(nmenu, p_submenu)); } void DisplayServer::global_menu_set_item_accelerator(const String &p_menu_root, int p_idx, Key p_keycode) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_accelerator(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_keycode); } void DisplayServer::global_menu_set_item_disabled(const String &p_menu_root, int p_idx, bool p_disabled) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_disabled(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_disabled); } void DisplayServer::global_menu_set_item_hidden(const String &p_menu_root, int p_idx, bool p_hidden) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_hidden(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_hidden); } void DisplayServer::global_menu_set_item_tooltip(const String &p_menu_root, int p_idx, const String &p_tooltip) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_tooltip(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_tooltip); } void DisplayServer::global_menu_set_item_state(const String &p_menu_root, int p_idx, int p_state) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_state(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_state); } void DisplayServer::global_menu_set_item_max_states(const String &p_menu_root, int p_idx, int p_max_states) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_max_states(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_max_states); } void DisplayServer::global_menu_set_item_icon(const String &p_menu_root, int p_idx, const Ref<Texture2D> &p_icon) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_icon(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_icon); } void DisplayServer::global_menu_set_item_indentation_level(const String &p_menu_root, int p_idx, int p_level) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->set_item_indentation_level(_get_rid_from_name(nmenu, p_menu_root), p_idx, p_level); } int DisplayServer::global_menu_get_item_count(const String &p_menu_root) const { - WARN_PRINT("Global menus not supported by this display server."); - return 0; + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, 0); + return nmenu->get_item_count(_get_rid_from_name(nmenu, p_menu_root)); } void DisplayServer::global_menu_remove_item(const String &p_menu_root, int p_idx) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + nmenu->remove_item(_get_rid_from_name(nmenu, p_menu_root), p_idx); } void DisplayServer::global_menu_clear(const String &p_menu_root) { - WARN_PRINT("Global menus not supported by this display server."); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL(nmenu); + RID rid = _get_rid_from_name(nmenu, p_menu_root); + nmenu->clear(rid); + if (!nmenu->is_system_menu(rid)) { + nmenu->free_menu(rid); + menu_names.erase(p_menu_root); + } } Dictionary DisplayServer::global_menu_get_system_menu_roots() const { - WARN_PRINT("Global menus not supported by this display server."); - return Dictionary(); + NativeMenu *nmenu = NativeMenu::get_singleton(); + ERR_FAIL_NULL_V(nmenu, Dictionary()); + + Dictionary out; + if (nmenu->has_system_menu(NativeMenu::DOCK_MENU_ID)) { + out["_dock"] = "@Dock"; + } + if (nmenu->has_system_menu(NativeMenu::APPLICATION_MENU_ID)) { + out["_apple"] = "@Apple"; + } + if (nmenu->has_system_menu(NativeMenu::WINDOW_MENU_ID)) { + out["_window"] = "Window"; + } + if (nmenu->has_system_menu(NativeMenu::HELP_MENU_ID)) { + out["_help"] = "Help"; + } + return out; } +#endif + bool DisplayServer::tts_is_speaking() const { WARN_PRINT("TTS is not supported by this display server."); return false; @@ -523,22 +645,22 @@ void DisplayServer::enable_for_stealing_focus(OS::ProcessID pid) { Error DisplayServer::dialog_show(String p_title, String p_description, Vector<String> p_buttons, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); - return OK; + return ERR_UNAVAILABLE; } Error DisplayServer::dialog_input_text(String p_title, String p_description, String p_partial, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); - return OK; + return ERR_UNAVAILABLE; } Error DisplayServer::file_dialog_show(const String &p_title, const String &p_current_directory, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); - return OK; + return ERR_UNAVAILABLE; } Error DisplayServer::file_dialog_with_options_show(const String &p_title, const String &p_current_directory, const String &p_root, const String &p_filename, bool p_show_hidden, FileDialogMode p_mode, const Vector<String> &p_filters, const TypedArray<Dictionary> &p_options, const Callable &p_callback) { WARN_PRINT("Native dialogs not supported by this display server."); - return OK; + return ERR_UNAVAILABLE; } int DisplayServer::keyboard_get_layout_count() const { @@ -639,6 +761,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("help_set_search_callbacks", "search_callback", "action_callback"), &DisplayServer::help_set_search_callbacks); +#ifndef DISABLE_DEPRECATED ClassDB::bind_method(D_METHOD("global_menu_set_popup_callbacks", "menu_root", "open_callback", "close_callback"), &DisplayServer::global_menu_set_popup_callbacks); ClassDB::bind_method(D_METHOD("global_menu_add_submenu_item", "menu_root", "label", "submenu", "index"), &DisplayServer::global_menu_add_submenu_item, DEFVAL(-1)); ClassDB::bind_method(D_METHOD("global_menu_add_item", "menu_root", "label", "callback", "key_callback", "tag", "accelerator", "index"), &DisplayServer::global_menu_add_item, DEFVAL(Callable()), DEFVAL(Callable()), DEFVAL(Variant()), DEFVAL(Key::NONE), DEFVAL(-1)); @@ -694,6 +817,7 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("global_menu_clear", "menu_root"), &DisplayServer::global_menu_clear); ClassDB::bind_method(D_METHOD("global_menu_get_system_menu_roots"), &DisplayServer::global_menu_get_system_menu_roots); +#endif ClassDB::bind_method(D_METHOD("tts_is_speaking"), &DisplayServer::tts_is_speaking); ClassDB::bind_method(D_METHOD("tts_is_paused"), &DisplayServer::tts_is_paused); @@ -865,7 +989,9 @@ void DisplayServer::_bind_methods() { ClassDB::bind_method(D_METHOD("tablet_get_current_driver"), &DisplayServer::tablet_get_current_driver); ClassDB::bind_method(D_METHOD("tablet_set_current_driver", "name"), &DisplayServer::tablet_set_current_driver); +#ifndef DISABLE_DEPRECATED BIND_ENUM_CONSTANT(FEATURE_GLOBAL_MENU); +#endif BIND_ENUM_CONSTANT(FEATURE_SUBWINDOWS); BIND_ENUM_CONSTANT(FEATURE_TOUCHSCREEN); BIND_ENUM_CONSTANT(FEATURE_MOUSE); @@ -888,6 +1014,8 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(FEATURE_SCREEN_CAPTURE); BIND_ENUM_CONSTANT(FEATURE_STATUS_INDICATOR); BIND_ENUM_CONSTANT(FEATURE_NATIVE_HELP); + BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_INPUT); + BIND_ENUM_CONSTANT(FEATURE_NATIVE_DIALOG_FILE); BIND_ENUM_CONSTANT(MOUSE_MODE_VISIBLE); BIND_ENUM_CONSTANT(MOUSE_MODE_HIDDEN); @@ -987,6 +1115,43 @@ void DisplayServer::_bind_methods() { BIND_ENUM_CONSTANT(TTS_UTTERANCE_BOUNDARY); } +Ref<Image> DisplayServer::_get_cursor_image_from_resource(const Ref<Resource> &p_cursor, const Vector2 &p_hotspot, Rect2 &r_atlas_rect) { + Ref<Image> image; + ERR_FAIL_COND_V_MSG(p_hotspot.x < 0 || p_hotspot.y < 0, image, "Hotspot outside cursor image."); + + Size2 texture_size; + + Ref<Texture2D> texture = p_cursor; + if (texture.is_valid()) { + Ref<AtlasTexture> atlas_texture = p_cursor; + + if (atlas_texture.is_valid()) { + texture = atlas_texture->get_atlas(); + r_atlas_rect.size = texture->get_size(); + r_atlas_rect.position = atlas_texture->get_region().position; + texture_size = atlas_texture->get_region().size; + } else { + texture_size = texture->get_size(); + } + image = texture->get_image(); + } else { + image = p_cursor; + ERR_FAIL_COND_V(image.is_null(), image); + texture_size = image->get_size(); + } + + ERR_FAIL_COND_V_MSG(p_hotspot.x > texture_size.width || p_hotspot.y > texture_size.height, image, "Hotspot outside cursor image."); + ERR_FAIL_COND_V_MSG(texture_size.width > 256 || texture_size.height > 256, image, "Cursor image too big. Max supported size is 256x256."); + + ERR_FAIL_COND_V(image.is_null(), image); + if (image->is_compressed()) { + image = image->duplicate(true); + Error err = image->decompress(); + ERR_FAIL_COND_V_MSG(err != OK, Ref<Image>(), "Couldn't decompress VRAM-compressed custom mouse cursor image. Switch to a lossless compression mode in the Import dock."); + } + return image; +} + void DisplayServer::register_create_function(const char *p_name, CreateFunction p_function, GetRenderingDriversFunction p_get_drivers) { ERR_FAIL_COND(server_create_count == MAX_SERVERS); // Headless display server is always last diff --git a/servers/display_server.h b/servers/display_server.h index 0f6c43ebe0..f1a98c2c17 100644 --- a/servers/display_server.h +++ b/servers/display_server.h @@ -36,7 +36,10 @@ #include "core/os/os.h" #include "core/variant/callable.h" +#include "display/native_menu.h" + class Texture2D; +class Image; class DisplayServer : public Object { GDCLASS(DisplayServer, Object) @@ -44,6 +47,12 @@ class DisplayServer : public Object { static DisplayServer *singleton; static bool hidpi_allowed; +#ifndef DISABLE_DEPRECATED + mutable HashMap<String, RID> menu_names; + + RID _get_rid_from_name(NativeMenu *p_nmenu, const String &p_menu_root) const; +#endif + public: _FORCE_INLINE_ static DisplayServer *get_singleton() { return singleton; @@ -86,6 +95,8 @@ private: protected: static void _bind_methods(); + static Ref<Image> _get_cursor_image_from_resource(const Ref<Resource> &p_cursor, const Vector2 &p_hotspot, Rect2 &r_atlas_rect); + enum { MAX_SERVERS = 64 }; @@ -103,7 +114,9 @@ protected: public: enum Feature { +#ifndef DISABLE_DEPRECATED FEATURE_GLOBAL_MENU, +#endif FEATURE_SUBWINDOWS, FEATURE_TOUCHSCREEN, FEATURE_MOUSE, @@ -127,6 +140,8 @@ public: FEATURE_SCREEN_CAPTURE, FEATURE_STATUS_INDICATOR, FEATURE_NATIVE_HELP, + FEATURE_NATIVE_DIALOG_INPUT, + FEATURE_NATIVE_DIALOG_FILE, }; virtual bool has_feature(Feature p_feature) const = 0; @@ -134,6 +149,7 @@ public: virtual void help_set_search_callbacks(const Callable &p_search_callback = Callable(), const Callable &p_action_callback = Callable()); +#ifndef DISABLE_DEPRECATED virtual void global_menu_set_popup_callbacks(const String &p_menu_root, const Callable &p_open_callback = Callable(), const Callable &p_close_callback = Callable()); virtual int global_menu_add_submenu_item(const String &p_menu_root, const String &p_label, const String &p_submenu, int p_index = -1); @@ -190,6 +206,7 @@ public: virtual void global_menu_clear(const String &p_menu_root); virtual Dictionary global_menu_get_system_menu_roots() const; +#endif struct TTSUtterance { String text; diff --git a/servers/display_server_headless.h b/servers/display_server_headless.h index af13f8db21..7a44645b1e 100644 --- a/servers/display_server_headless.h +++ b/servers/display_server_headless.h @@ -51,6 +51,8 @@ private: return memnew(DisplayServerHeadless()); } + NativeMenu *native_menu = nullptr; + public: bool has_feature(Feature p_feature) const override { return false; } String get_name() const override { return "headless"; } @@ -132,8 +134,15 @@ public: void set_icon(const Ref<Image> &p_icon) override {} - DisplayServerHeadless() {} - ~DisplayServerHeadless() {} + DisplayServerHeadless() { + native_menu = memnew(NativeMenu); + } + ~DisplayServerHeadless() { + if (native_menu) { + memdelete(native_menu); + native_menu = nullptr; + } + } }; #endif // DISPLAY_SERVER_HEADLESS_H diff --git a/servers/extensions/SCsub b/servers/extensions/SCsub index ba73353f2a..95c7f5d319 100644 --- a/servers/extensions/SCsub +++ b/servers/extensions/SCsub @@ -4,4 +4,7 @@ Import("env") env_object = env.Clone() -env_object.add_source_files(env.servers_sources, "*.cpp") +env_object.add_source_files(env.servers_sources, "physics_server_2d_extension.cpp") + +if not env["disable_3d"]: + env_object.add_source_files(env.servers_sources, "physics_server_3d_extension.cpp") diff --git a/servers/navigation_server_3d.cpp b/servers/navigation_server_3d.cpp index 00db1440f6..e460bcb9c6 100644 --- a/servers/navigation_server_3d.cpp +++ b/servers/navigation_server_3d.cpp @@ -29,7 +29,9 @@ /**************************************************************************/ #include "navigation_server_3d.h" + #include "core/config/project_settings.h" +#include "scene/main/node.h" NavigationServer3D *NavigationServer3D::singleton = nullptr; @@ -233,6 +235,7 @@ NavigationServer3D::NavigationServer3D() { GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_multiple_threads", true); GLOBAL_DEF("navigation/avoidance/thread_model/avoidance_use_high_priority_threads", true); + GLOBAL_DEF("navigation/baking/use_crash_prevention_checks", true); GLOBAL_DEF("navigation/baking/thread_model/baking_use_multiple_threads", true); GLOBAL_DEF("navigation/baking/thread_model/baking_use_high_priority_threads", true); @@ -291,7 +294,11 @@ void NavigationServer3D::set_debug_enabled(bool p_enabled) { debug_enabled = p_enabled; if (debug_dirty) { + navigation_debug_dirty = true; callable_mp(this, &NavigationServer3D::_emit_navigation_debug_changed_signal).call_deferred(); + + avoidance_debug_dirty = true; + callable_mp(this, &NavigationServer3D::_emit_avoidance_debug_changed_signal).call_deferred(); } #endif // DEBUG_ENABLED } diff --git a/servers/physics_2d/godot_broad_phase_2d_bvh.h b/servers/physics_2d/godot_broad_phase_2d_bvh.h index 36fd1223b0..6c1fae5cb2 100644 --- a/servers/physics_2d/godot_broad_phase_2d_bvh.h +++ b/servers/physics_2d/godot_broad_phase_2d_bvh.h @@ -38,7 +38,7 @@ #include "core/math/vector2.h" class GodotBroadPhase2DBVH : public GodotBroadPhase2D { - template <class T> + template <typename T> class UserPairTestFunction { public: static bool user_pair_check(const T *p_a, const T *p_b) { @@ -47,7 +47,7 @@ class GodotBroadPhase2DBVH : public GodotBroadPhase2D { } }; - template <class T> + template <typename T> class UserCullTestFunction { public: static bool user_cull_check(const T *p_a, const T *p_b) { diff --git a/servers/physics_2d/godot_collision_solver_2d_sat.cpp b/servers/physics_2d/godot_collision_solver_2d_sat.cpp index c85fdc592a..daa9982b2e 100644 --- a/servers/physics_2d/godot_collision_solver_2d_sat.cpp +++ b/servers/physics_2d/godot_collision_solver_2d_sat.cpp @@ -171,7 +171,7 @@ static void _generate_contacts_from_supports(const Vector2 *p_points_A, int p_po contacts_func(points_A, pointcount_A, points_B, pointcount_B, p_collector); } -template <class ShapeA, class ShapeB, bool castA = false, bool castB = false, bool withMargin = false> +template <typename ShapeA, typename ShapeB, bool castA = false, bool castB = false, bool withMargin = false> class SeparatorAxisTest2D { const ShapeA *shape_A = nullptr; const ShapeB *shape_B = nullptr; diff --git a/servers/physics_3d/godot_broad_phase_3d_bvh.h b/servers/physics_3d/godot_broad_phase_3d_bvh.h index 6279658ec4..63968dea64 100644 --- a/servers/physics_3d/godot_broad_phase_3d_bvh.h +++ b/servers/physics_3d/godot_broad_phase_3d_bvh.h @@ -36,7 +36,7 @@ #include "core/math/bvh.h" class GodotBroadPhase3DBVH : public GodotBroadPhase3D { - template <class T> + template <typename T> class UserPairTestFunction { public: static bool user_pair_check(const T *p_a, const T *p_b) { @@ -45,7 +45,7 @@ class GodotBroadPhase3DBVH : public GodotBroadPhase3D { } }; - template <class T> + template <typename T> class UserCullTestFunction { public: static bool user_cull_check(const T *p_a, const T *p_b) { diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp index 3aa2f256c1..c53c8481f4 100644 --- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp +++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp @@ -612,7 +612,7 @@ static void _generate_contacts_from_supports(const Vector3 *p_points_A, int p_po contacts_func(points_A, pointcount_A, points_B, pointcount_B, p_callback); } -template <class ShapeA, class ShapeB, bool withMargin = false> +template <typename ShapeA, typename ShapeB, bool withMargin = false> class SeparatorAxisTest { const ShapeA *shape_A = nullptr; const ShapeB *shape_B = nullptr; @@ -1962,7 +1962,7 @@ static void _collision_cylinder_face(const GodotShape3D *p_a, const Transform3D // Points of B, cylinder lateral surface. for (int i = 0; i < 3; i++) { - const Vector3 &point = vertex[i]; + const Vector3 point = vertex[i] - p_transform_a.origin; Vector3 axis = Plane(cyl_axis).project(point).normalized(); if (axis.dot(normal) < 0.0) { axis *= -1.0; diff --git a/servers/physics_3d/godot_shape_3d.cpp b/servers/physics_3d/godot_shape_3d.cpp index 872d26aff6..ea389ff59c 100644 --- a/servers/physics_3d/godot_shape_3d.cpp +++ b/servers/physics_3d/godot_shape_3d.cpp @@ -2016,9 +2016,7 @@ void GodotHeightMapShape3D::_get_cell(const Vector3 &p_point, int &r_x, int &r_y Vector3 pos_local = shape_aabb.position + local_origin; Vector3 clamped_point(p_point); - clamped_point.x = CLAMP(p_point.x, pos_local.x, pos_local.x + shape_aabb.size.x); - clamped_point.y = CLAMP(p_point.y, pos_local.y, pos_local.y + shape_aabb.size.y); - clamped_point.z = CLAMP(p_point.z, pos_local.z, pos_local.z + shape_aabb.size.z); + clamped_point = p_point.clamp(pos_local, pos_local + shape_aabb.size); r_x = (clamped_point.x < 0.0) ? (clamped_point.x - 0.5) : (clamped_point.x + 0.5); r_y = (clamped_point.y < 0.0) ? (clamped_point.y - 0.5) : (clamped_point.y + 0.5); diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp index 0c2b935554..e621977326 100644 --- a/servers/physics_3d/godot_soft_body_3d.cpp +++ b/servers/physics_3d/godot_soft_body_3d.cpp @@ -595,7 +595,7 @@ void GodotSoftBody3D::generate_bending_constraints(int p_distance) { const uint32_t adj_size = n * n; unsigned *adj = memnew_arr(unsigned, adj_size); -#define IDX(_x_, _y_) ((_y_)*n + (_x_)) +#define IDX(_x_, _y_) ((_y_) * n + (_x_)) for (j = 0; j < n; ++j) { for (i = 0; i < n; ++i) { int idx_ij = j * n + i; diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp index 46b6689533..9a6ba776b4 100644 --- a/servers/physics_3d/godot_space_3d.cpp +++ b/servers/physics_3d/godot_space_3d.cpp @@ -655,7 +655,7 @@ bool GodotSpace3D::test_body_motion(GodotBody3D *p_body, const PhysicsServer3D:: //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); + ERR_FAIL_COND_V(p_parameters.max_collisions < 0 || p_parameters.max_collisions > PhysicsServer3D::MotionResult::MAX_COLLISIONS, false); if (r_result) { *r_result = PhysicsServer3D::MotionResult(); diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp index 686388f237..f56ef11c14 100644 --- a/servers/physics_server_3d.cpp +++ b/servers/physics_server_3d.cpp @@ -28,6 +28,8 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /**************************************************************************/ +#ifndef _3D_DISABLED + #include "physics_server_3d.h" #include "core/config/project_settings.h" @@ -983,6 +985,9 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_DAMPING); BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_TARGET_VELOCITY); BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_MOTOR_FORCE_LIMIT); + BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_STIFFNESS); + BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_DAMPING); + BIND_ENUM_CONSTANT(G6DOF_JOINT_LINEAR_SPRING_EQUILIBRIUM_POINT); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LOWER_LIMIT); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_UPPER_LIMIT); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_LIMIT_SOFTNESS); @@ -992,11 +997,18 @@ void PhysicsServer3D::_bind_methods() { BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_ERP); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_TARGET_VELOCITY); BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_MOTOR_FORCE_LIMIT); + BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_STIFFNESS); + BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_DAMPING); + BIND_ENUM_CONSTANT(G6DOF_JOINT_ANGULAR_SPRING_EQUILIBRIUM_POINT); + BIND_ENUM_CONSTANT(G6DOF_JOINT_MAX); BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_LIMIT); BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_LIMIT); + BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_ANGULAR_SPRING); + BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_SPRING); BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_MOTOR); BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_ENABLE_LINEAR_MOTOR); + BIND_ENUM_CONSTANT(G6DOF_JOINT_FLAG_MAX); ClassDB::bind_method(D_METHOD("joint_get_type", "joint"), &PhysicsServer3D::joint_get_type); @@ -1213,3 +1225,5 @@ PhysicsServer3DManager::PhysicsServer3DManager() { PhysicsServer3DManager::~PhysicsServer3DManager() { singleton = nullptr; } + +#endif // _3D_DISABLED diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h index 248b6cd8f8..ea785fa03f 100644 --- a/servers/physics_server_3d.h +++ b/servers/physics_server_3d.h @@ -31,6 +31,8 @@ #ifndef PHYSICS_SERVER_3D_H #define PHYSICS_SERVER_3D_H +#ifndef _3D_DISABLED + #include "core/io/resource.h" #include "core/object/class_db.h" #include "core/object/gdvirtual.gen.inc" @@ -1055,4 +1057,6 @@ VARIANT_ENUM_CAST(PhysicsServer3D::G6DOFJointAxisFlag); VARIANT_ENUM_CAST(PhysicsServer3D::AreaBodyStatus); VARIANT_ENUM_CAST(PhysicsServer3D::ProcessInfo); +#endif // _3D_DISABLED + #endif // PHYSICS_SERVER_3D_H diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 380500769c..c03c0b7a40 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -43,6 +43,7 @@ #include "audio/effects/audio_effect_distortion.h" #include "audio/effects/audio_effect_eq.h" #include "audio/effects/audio_effect_filter.h" +#include "audio/effects/audio_effect_hard_limiter.h" #include "audio/effects/audio_effect_limiter.h" #include "audio/effects/audio_effect_panner.h" #include "audio/effects/audio_effect_phaser.h" @@ -56,6 +57,7 @@ #include "camera/camera_feed.h" #include "camera_server.h" #include "debugger/servers_debugger.h" +#include "display/native_menu.h" #include "display_server.h" #include "movie_writer/movie_writer.h" #include "movie_writer/movie_writer_mjpeg.h" @@ -76,12 +78,6 @@ #include "text/text_server_dummy.h" #include "text/text_server_extension.h" #include "text_server.h" -#include "xr/xr_face_tracker.h" -#include "xr/xr_hand_tracker.h" -#include "xr/xr_interface.h" -#include "xr/xr_interface_extension.h" -#include "xr/xr_positional_tracker.h" -#include "xr_server.h" // 2D physics and navigation. #include "navigation_server_2d.h" @@ -97,6 +93,13 @@ #include "physics_server_3d.h" #include "physics_server_3d_wrap_mt.h" #include "servers/extensions/physics_server_3d_extension.h" +#include "xr/xr_body_tracker.h" +#include "xr/xr_face_tracker.h" +#include "xr/xr_hand_tracker.h" +#include "xr/xr_interface.h" +#include "xr/xr_interface_extension.h" +#include "xr/xr_positional_tracker.h" +#include "xr_server.h" #endif // _3D_DISABLED ShaderTypes *shader_types = nullptr; @@ -161,25 +164,12 @@ void register_server_types() { GDREGISTER_ABSTRACT_CLASS(RenderingServer); GDREGISTER_CLASS(AudioServer); - GDREGISTER_ABSTRACT_CLASS(NavigationServer2D); - GDREGISTER_ABSTRACT_CLASS(NavigationServer3D); - GDREGISTER_CLASS(NavigationPathQueryParameters2D); - GDREGISTER_CLASS(NavigationPathQueryParameters3D); - GDREGISTER_CLASS(NavigationPathQueryResult2D); - GDREGISTER_CLASS(NavigationPathQueryResult3D); + GDREGISTER_CLASS(NativeMenu); - GDREGISTER_CLASS(XRServer); GDREGISTER_CLASS(CameraServer); GDREGISTER_ABSTRACT_CLASS(RenderingDevice); - GDREGISTER_ABSTRACT_CLASS(XRInterface); - GDREGISTER_CLASS(XRHandTracker); - 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(XRFaceTracker); - GDREGISTER_CLASS(AudioStream); GDREGISTER_CLASS(AudioStreamPlayback); GDREGISTER_VIRTUAL_CLASS(AudioStreamPlaybackResampled); @@ -221,6 +211,7 @@ void register_server_types() { GDREGISTER_CLASS(AudioEffectDelay); GDREGISTER_CLASS(AudioEffectCompressor); GDREGISTER_CLASS(AudioEffectLimiter); + GDREGISTER_CLASS(AudioEffectHardLimiter); GDREGISTER_CLASS(AudioEffectPitchShift); GDREGISTER_CLASS(AudioEffectPhaser); @@ -298,6 +289,10 @@ void register_server_types() { PhysicsServer2DManager::get_singleton()->register_server("GodotPhysics2D", callable_mp_static(_createGodotPhysics2DCallback)); PhysicsServer2DManager::get_singleton()->set_default_server("GodotPhysics2D"); + GDREGISTER_ABSTRACT_CLASS(NavigationServer2D); + GDREGISTER_CLASS(NavigationPathQueryParameters2D); + GDREGISTER_CLASS(NavigationPathQueryResult2D); + #ifndef _3D_DISABLED // Physics 3D GDREGISTER_CLASS(PhysicsServer3DManager); @@ -327,8 +322,21 @@ void register_server_types() { PhysicsServer3DManager::get_singleton()->register_server("GodotPhysics3D", callable_mp_static(_createGodotPhysics3DCallback)); PhysicsServer3DManager::get_singleton()->set_default_server("GodotPhysics3D"); + + GDREGISTER_ABSTRACT_CLASS(XRInterface); + GDREGISTER_CLASS(XRBodyTracker); + GDREGISTER_CLASS(XRFaceTracker); + GDREGISTER_CLASS(XRHandTracker); + 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(XRServer); #endif // _3D_DISABLED + GDREGISTER_ABSTRACT_CLASS(NavigationServer3D); + GDREGISTER_CLASS(NavigationPathQueryParameters3D); + GDREGISTER_CLASS(NavigationPathQueryResult3D); + writer_mjpeg = memnew(MovieWriterMJPEG); MovieWriter::add_writer(writer_mjpeg); @@ -352,17 +360,19 @@ void unregister_server_types() { void register_server_singletons() { OS::get_singleton()->benchmark_begin_measure("Servers", "Register Singletons"); + Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton(), "AudioServer")); + Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer")); Engine::get_singleton()->add_singleton(Engine::Singleton("DisplayServer", DisplayServer::get_singleton(), "DisplayServer")); + Engine::get_singleton()->add_singleton(Engine::Singleton("NativeMenu", NativeMenu::get_singleton(), "NativeMenu")); + Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton(), "NavigationServer2D")); + Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton(), "NavigationServer3D")); Engine::get_singleton()->add_singleton(Engine::Singleton("RenderingServer", RenderingServer::get_singleton(), "RenderingServer")); - Engine::get_singleton()->add_singleton(Engine::Singleton("AudioServer", AudioServer::get_singleton(), "AudioServer")); + Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer2D", PhysicsServer2D::get_singleton(), "PhysicsServer2D")); #ifndef _3D_DISABLED Engine::get_singleton()->add_singleton(Engine::Singleton("PhysicsServer3D", PhysicsServer3D::get_singleton(), "PhysicsServer3D")); -#endif // _3D_DISABLED - Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer2D", NavigationServer2D::get_singleton(), "NavigationServer2D")); - Engine::get_singleton()->add_singleton(Engine::Singleton("NavigationServer3D", NavigationServer3D::get_singleton(), "NavigationServer3D")); Engine::get_singleton()->add_singleton(Engine::Singleton("XRServer", XRServer::get_singleton(), "XRServer")); - Engine::get_singleton()->add_singleton(Engine::Singleton("CameraServer", CameraServer::get_singleton(), "CameraServer")); +#endif // _3D_DISABLED OS::get_singleton()->benchmark_end_measure("Servers", "Register Singletons"); } diff --git a/servers/rendering/dummy/storage/light_storage.h b/servers/rendering/dummy/storage/light_storage.h index 61a825f8c5..a76305cdaa 100644 --- a/servers/rendering/dummy/storage/light_storage.h +++ b/servers/rendering/dummy/storage/light_storage.h @@ -135,6 +135,7 @@ public: virtual RID reflection_probe_instance_create(RID p_probe) override { return RID(); } virtual void reflection_probe_instance_free(RID p_instance) override {} virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override {} + virtual bool reflection_probe_has_atlas_index(RID p_instance) override { return false; } virtual void reflection_probe_release_atlas_index(RID p_instance) override {} virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override { return false; } virtual bool reflection_probe_instance_has_reflection(RID p_instance) override { return false; } diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp index 65fcdb9751..e32164ea98 100644 --- a/servers/rendering/renderer_canvas_cull.cpp +++ b/servers/rendering/renderer_canvas_cull.cpp @@ -32,22 +32,20 @@ #include "core/config/project_settings.h" #include "core/math/geometry_2d.h" +#include "core/math/transform_interpolator.h" #include "renderer_viewport.h" #include "rendering_server_default.h" #include "rendering_server_globals.h" #include "servers/rendering/storage/texture_storage.h" -void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) { +void RendererCanvasCull::_render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RenderingServer::CanvasItemTextureFilter p_default_filter, RenderingServer::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info) { RENDER_TIMESTAMP("Cull CanvasItem Tree"); memset(z_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); memset(z_last_list, 0, z_range * sizeof(RendererCanvasRender::Item *)); for (int i = 0; i < p_child_item_count; i++) { - _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, p_canvas_cull_mask); - } - if (p_canvas_item) { - _cull_canvas_item(p_canvas_item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, p_canvas_cull_mask); + _cull_canvas_item(p_child_items[i].item, p_transform, p_clip_rect, Color(1, 1, 1, 1), 0, z_list, z_last_list, nullptr, nullptr, true, p_canvas_cull_mask, p_child_items[i].mirror, 1); } RendererCanvasRender::Item *list = nullptr; @@ -84,7 +82,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2 if (r_items) { r_items[r_index] = child_items[i]; child_items[i]->ysort_xform = p_transform; - child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.columns[2]); + child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform_curr.columns[2]); child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : nullptr; child_items[i]->ysort_modulate = p_modulate; child_items[i]->ysort_index = r_index; @@ -101,7 +99,7 @@ void _collect_ysort_children(RendererCanvasCull::Item *p_canvas_item, Transform2 r_index++; if (child_items[i]->sort_y) { - _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z); + _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform_curr, child_items[i]->use_parent_material ? p_material_owner : child_items[i], p_modulate * child_items[i]->modulate, r_items, r_index, abs_z); } } } @@ -223,7 +221,7 @@ void RendererCanvasCull::_attach_canvas_item_for_draw(RendererCanvasCull::Item * } } -void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask) { +void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times) { Item *ci = p_canvas_item; if (!ci->visible) { @@ -247,17 +245,40 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 } } - Transform2D xform = ci->xform; + Transform2D final_xform; + if (!_interpolation_data.interpolation_enabled || !ci->interpolated) { + final_xform = ci->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(ci->xform_prev, ci->xform_curr, final_xform, f); + } + Transform2D parent_xform = p_parent_xform; + Point2 repeat_size = p_repeat_size; + int repeat_times = p_repeat_times; + + if (ci->repeat_source) { + repeat_size = ci->repeat_size; + repeat_times = ci->repeat_times; + } else { + ci->repeat_size = repeat_size; + ci->repeat_times = repeat_times; + + if (repeat_size.x || repeat_size.y) { + rect.size += repeat_size * repeat_times / final_xform.get_scale(); + rect.position -= repeat_size * (repeat_times / 2); + } + } + if (snapping_2d_transforms_to_pixel) { - xform.columns[2] = xform.columns[2].round(); + final_xform.columns[2] = final_xform.columns[2].round(); parent_xform.columns[2] = parent_xform.columns[2].round(); } - xform = parent_xform * xform; + final_xform = parent_xform * final_xform; - Rect2 global_rect = xform.xform(rect); + Rect2 global_rect = final_xform.xform(rect); global_rect.position += p_clip_rect.position; if (ci->use_parent_material && p_material_owner) { @@ -311,7 +332,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 child_item_count = ci->ysort_children_count + 1; child_items = (Item **)alloca(child_item_count * sizeof(Item *)); - ci->ysort_xform = ci->xform.affine_inverse(); + ci->ysort_xform = final_xform.affine_inverse(); ci->ysort_pos = Vector2(); ci->ysort_modulate = Color(1, 1, 1, 1); ci->ysort_index = 0; @@ -324,7 +345,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 sorter.sort(child_items, child_item_count); for (i = 0; i < child_item_count; i++) { - _cull_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask); + _cull_canvas_item(child_items[i], final_xform * child_items[i]->ysort_xform, p_clip_rect, modulate * child_items[i]->ysort_modulate, child_items[i]->ysort_parent_abs_z_index, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner, false, p_canvas_cull_mask, repeat_size, repeat_times); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; @@ -334,7 +355,7 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 canvas_group_from = r_z_last_list[zidx]; } - _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); + _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); } } else { RendererCanvasRender::Item *canvas_group_from = nullptr; @@ -348,14 +369,14 @@ void RendererCanvasCull::_cull_canvas_item(Item *p_canvas_item, const Transform2 if (!child_items[i]->behind && !use_canvas_group) { continue; } - _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask); + _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times); } - _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); + _attach_canvas_item_for_draw(ci, p_canvas_clip, r_z_list, r_z_last_list, final_xform, p_clip_rect, global_rect, modulate, p_z, p_material_owner, use_canvas_group, canvas_group_from); for (int i = 0; i < child_item_count; i++) { if (child_items[i]->behind || use_canvas_group) { continue; } - _cull_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask); + _cull_canvas_item(child_items[i], final_xform, p_clip_rect, modulate, p_z, r_z_list, r_z_last_list, (Item *)ci->final_clip_owner, p_material_owner, true, p_canvas_cull_mask, repeat_size, repeat_times); } } } @@ -374,38 +395,7 @@ void RendererCanvasCull::render_canvas(RID p_render_target, Canvas *p_canvas, co int l = p_canvas->child_items.size(); Canvas::ChildItem *ci = p_canvas->child_items.ptrw(); - bool has_mirror = false; - for (int i = 0; i < l; i++) { - if (ci[i].mirror.x || ci[i].mirror.y) { - has_mirror = true; - break; - } - } - - if (!has_mirror) { - _render_canvas_item_tree(p_render_target, ci, l, nullptr, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask, r_render_info); - - } else { - //used for parallaxlayer mirroring - for (int i = 0; i < l; i++) { - const Canvas::ChildItem &ci2 = p_canvas->child_items[i]; - _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask, r_render_info); - - //mirroring (useful for scrolling backgrounds) - if (ci2.mirror.x != 0) { - Transform2D xform2 = p_transform * Transform2D(0, Vector2(ci2.mirror.x, 0)); - _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask, r_render_info); - } - if (ci2.mirror.y != 0) { - Transform2D xform2 = p_transform * Transform2D(0, Vector2(0, ci2.mirror.y)); - _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask, r_render_info); - } - if (ci2.mirror.y != 0 && ci2.mirror.x != 0) { - Transform2D xform2 = p_transform * Transform2D(0, ci2.mirror); - _render_canvas_item_tree(p_render_target, nullptr, 0, ci2.item, xform2, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask, r_render_info); - } - } - } + _render_canvas_item_tree(p_render_target, ci, l, p_transform, p_clip_rect, p_canvas->modulate, p_lights, p_directional_lights, p_default_filter, p_default_repeat, p_snap_2d_vertices_to_pixel, canvas_cull_mask, r_render_info); RENDER_TIMESTAMP("< Render Canvas"); } @@ -432,6 +422,15 @@ void RendererCanvasCull::canvas_set_item_mirroring(RID p_canvas, RID p_item, con canvas->child_items.write[idx].mirror = p_mirroring; } +void RendererCanvasCull::canvas_set_item_repeat(RID p_item, const Point2 &p_repeat_size, int p_repeat_times) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_NULL(canvas_item); + + canvas_item->repeat_source = true; + canvas_item->repeat_size = p_repeat_size; + canvas_item->repeat_times = p_repeat_times; +} + void RendererCanvasCull::canvas_set_modulate(RID p_canvas, const Color &p_color) { Canvas *canvas = canvas_owner.get_or_null(p_canvas); ERR_FAIL_NULL(canvas); @@ -521,7 +520,16 @@ void RendererCanvasCull::canvas_item_set_transform(RID p_item, const Transform2D Item *canvas_item = canvas_item_owner.get_or_null(p_item); ERR_FAIL_NULL(canvas_item); - canvas_item->xform = p_transform; + if (_interpolation_data.interpolation_enabled && canvas_item->interpolated) { + if (!canvas_item->on_interpolate_transform_list) { + _interpolation_data.canvas_item_transform_update_list_curr->push_back(p_item); + canvas_item->on_interpolate_transform_list = true; + } else { + DEV_ASSERT(_interpolation_data.canvas_item_transform_update_list_curr->size() > 0); + } + } + + canvas_item->xform_curr = p_transform; } void RendererCanvasCull::canvas_item_set_visibility_layer(RID p_item, uint32_t p_visibility_layer) { @@ -1631,6 +1639,26 @@ bool RendererCanvasCull::canvas_item_get_debug_redraw() const { return debug_redraw; } +void RendererCanvasCull::canvas_item_set_interpolated(RID p_item, bool p_interpolated) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_NULL(canvas_item); + canvas_item->interpolated = p_interpolated; +} + +void RendererCanvasCull::canvas_item_reset_physics_interpolation(RID p_item) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_NULL(canvas_item); + canvas_item->xform_prev = canvas_item->xform_curr; +} + +// Useful especially for origin shifting. +void RendererCanvasCull::canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) { + Item *canvas_item = canvas_item_owner.get_or_null(p_item); + ERR_FAIL_NULL(canvas_item); + canvas_item->xform_prev = p_transform * canvas_item->xform_prev; + canvas_item->xform_curr = p_transform * canvas_item->xform_curr; +} + 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.get_or_null(p_item); ERR_FAIL_NULL(canvas_item); @@ -1729,7 +1757,16 @@ void RendererCanvasCull::canvas_light_set_transform(RID p_light, const Transform RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); ERR_FAIL_NULL(clight); - clight->xform = p_transform; + if (_interpolation_data.interpolation_enabled && clight->interpolated) { + if (!clight->on_interpolate_transform_list) { + _interpolation_data.canvas_light_transform_update_list_curr->push_back(p_light); + clight->on_interpolate_transform_list = true; + } else { + DEV_ASSERT(_interpolation_data.canvas_light_transform_update_list_curr->size() > 0); + } + } + + clight->xform_curr = p_transform; } void RendererCanvasCull::canvas_light_set_texture(RID p_light, RID p_texture) { @@ -1848,6 +1885,25 @@ void RendererCanvasCull::canvas_light_set_shadow_smooth(RID p_light, float p_smo clight->shadow_smooth = p_smooth; } +void RendererCanvasCull::canvas_light_set_interpolated(RID p_light, bool p_interpolated) { + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); + ERR_FAIL_NULL(clight); + clight->interpolated = p_interpolated; +} + +void RendererCanvasCull::canvas_light_reset_physics_interpolation(RID p_light) { + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); + ERR_FAIL_NULL(clight); + clight->xform_prev = clight->xform_curr; +} + +void RendererCanvasCull::canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) { + RendererCanvasRender::Light *clight = canvas_light_owner.get_or_null(p_light); + ERR_FAIL_NULL(clight); + clight->xform_prev = p_transform * clight->xform_prev; + clight->xform_curr = p_transform * clight->xform_curr; +} + RID RendererCanvasCull::canvas_light_occluder_allocate() { return canvas_light_occluder_owner.allocate_rid(); } @@ -1920,7 +1976,16 @@ void RendererCanvasCull::canvas_light_occluder_set_transform(RID p_occluder, con RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); ERR_FAIL_NULL(occluder); - occluder->xform = p_xform; + if (_interpolation_data.interpolation_enabled && occluder->interpolated) { + if (!occluder->on_interpolate_transform_list) { + _interpolation_data.canvas_light_occluder_transform_update_list_curr->push_back(p_occluder); + occluder->on_interpolate_transform_list = true; + } else { + DEV_ASSERT(_interpolation_data.canvas_light_occluder_transform_update_list_curr->size() > 0); + } + } + + occluder->xform_curr = p_xform; } void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) { @@ -1930,6 +1995,25 @@ void RendererCanvasCull::canvas_light_occluder_set_light_mask(RID p_occluder, in occluder->light_mask = p_mask; } +void RendererCanvasCull::canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); + ERR_FAIL_NULL(occluder); + occluder->interpolated = p_interpolated; +} + +void RendererCanvasCull::canvas_light_occluder_reset_physics_interpolation(RID p_occluder) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); + ERR_FAIL_NULL(occluder); + occluder->xform_prev = occluder->xform_curr; +} + +void RendererCanvasCull::canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) { + RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_occluder); + ERR_FAIL_NULL(occluder); + occluder->xform_prev = p_transform * occluder->xform_prev; + occluder->xform_curr = p_transform * occluder->xform_curr; +} + RID RendererCanvasCull::canvas_occluder_polygon_allocate() { return canvas_light_occluder_polygon_owner.allocate_rid(); } @@ -2084,6 +2168,7 @@ bool RendererCanvasCull::free(RID p_rid) { } else if (canvas_item_owner.owns(p_rid)) { Item *canvas_item = canvas_item_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(canvas_item, true); + _interpolation_data.notify_free_canvas_item(p_rid, *canvas_item); if (canvas_item->parent.is_valid()) { if (canvas_owner.owns(canvas_item->parent)) { @@ -2123,6 +2208,7 @@ bool RendererCanvasCull::free(RID p_rid) { } else if (canvas_light_owner.owns(p_rid)) { RendererCanvasRender::Light *canvas_light = canvas_light_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(canvas_light, true); + _interpolation_data.notify_free_canvas_light(p_rid, *canvas_light); if (canvas_light->canvas.is_valid()) { Canvas *canvas = canvas_owner.get_or_null(canvas_light->canvas); @@ -2138,6 +2224,7 @@ bool RendererCanvasCull::free(RID p_rid) { } else if (canvas_light_occluder_owner.owns(p_rid)) { RendererCanvasRender::LightOccluderInstance *occluder = canvas_light_occluder_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(occluder, true); + _interpolation_data.notify_free_canvas_light_occluder(p_rid, *occluder); if (occluder->polygon.is_valid()) { LightOccluderPolygon *occluder_poly = canvas_light_occluder_polygon_owner.get_or_null(occluder->polygon); @@ -2171,7 +2258,7 @@ bool RendererCanvasCull::free(RID p_rid) { return true; } -template <class T> +template <typename T> void RendererCanvasCull::_free_rids(T &p_owner, const char *p_type) { List<RID> owned; p_owner.get_owned_list(&owned); @@ -2195,6 +2282,81 @@ void RendererCanvasCull::finalize() { _free_rids(canvas_light_occluder_polygon_owner, "CanvasLightOccluderPolygon"); } +void RendererCanvasCull::tick() { + if (_interpolation_data.interpolation_enabled) { + update_interpolation_tick(true); + } +} + +void RendererCanvasCull::update_interpolation_tick(bool p_process) { +#define GODOT_UPDATE_INTERPOLATION_TICK(m_list_prev, m_list_curr, m_type, m_owner_list) \ + /* Detect any that were on the previous transform list that are no longer active. */ \ + for (unsigned int n = 0; n < _interpolation_data.m_list_prev->size(); n++) { \ + const RID &rid = (*_interpolation_data.m_list_prev)[n]; \ + m_type *item = m_owner_list.get_or_null(rid); \ + /* no longer active? (either the instance deleted or no longer being transformed) */ \ + if (item && !item->on_interpolate_transform_list) { \ + item->xform_prev = item->xform_curr; \ + } \ + } \ + /* and now for any in the transform list (being actively interpolated), */ \ + /* keep the previous transform value up to date and ready for next tick */ \ + if (p_process) { \ + for (unsigned int n = 0; n < _interpolation_data.m_list_curr->size(); n++) { \ + const RID &rid = (*_interpolation_data.m_list_curr)[n]; \ + m_type *item = m_owner_list.get_or_null(rid); \ + if (item) { \ + item->xform_prev = item->xform_curr; \ + item->on_interpolate_transform_list = false; \ + } \ + } \ + } \ + SWAP(_interpolation_data.m_list_curr, _interpolation_data.m_list_prev); \ + _interpolation_data.m_list_curr->clear(); + + GODOT_UPDATE_INTERPOLATION_TICK(canvas_item_transform_update_list_prev, canvas_item_transform_update_list_curr, Item, canvas_item_owner); + GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_transform_update_list_prev, canvas_light_transform_update_list_curr, RendererCanvasRender::Light, canvas_light_owner); + GODOT_UPDATE_INTERPOLATION_TICK(canvas_light_occluder_transform_update_list_prev, canvas_light_occluder_transform_update_list_curr, RendererCanvasRender::LightOccluderInstance, canvas_light_occluder_owner); + +#undef GODOT_UPDATE_INTERPOLATION_TICK +} + +void RendererCanvasCull::InterpolationData::notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item) { + r_canvas_item.on_interpolate_transform_list = false; + + if (!interpolation_enabled) { + return; + } + + // If the instance was on any of the lists, remove. + canvas_item_transform_update_list_curr->erase_multiple_unordered(p_rid); + canvas_item_transform_update_list_prev->erase_multiple_unordered(p_rid); +} + +void RendererCanvasCull::InterpolationData::notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light) { + r_canvas_light.on_interpolate_transform_list = false; + + if (!interpolation_enabled) { + return; + } + + // If the instance was on any of the lists, remove. + canvas_light_transform_update_list_curr->erase_multiple_unordered(p_rid); + canvas_light_transform_update_list_prev->erase_multiple_unordered(p_rid); +} + +void RendererCanvasCull::InterpolationData::notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder) { + r_canvas_light_occluder.on_interpolate_transform_list = false; + + if (!interpolation_enabled) { + return; + } + + // If the instance was on any of the lists, remove. + canvas_light_occluder_transform_update_list_curr->erase_multiple_unordered(p_rid); + canvas_light_occluder_transform_update_list_prev->erase_multiple_unordered(p_rid); +} + RendererCanvasCull::RendererCanvasCull() { z_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); z_last_list = (RendererCanvasRender::Item **)memalloc(z_range * sizeof(RendererCanvasRender::Item *)); diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h index 00f69766b1..961506ca28 100644 --- a/servers/rendering/renderer_canvas_cull.h +++ b/servers/rendering/renderer_canvas_cull.h @@ -170,7 +170,7 @@ public: RID_Owner<Item, true> canvas_item_owner; RID_Owner<RendererCanvasRender::Light, true> canvas_light_owner; - template <class T> + template <typename T> void _free_rids(T &p_owner, const char *p_type); bool disable_scale; @@ -187,8 +187,8 @@ public: _FORCE_INLINE_ void _attach_canvas_item_for_draw(Item *ci, Item *p_canvas_clip, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, const Transform2D &p_transform, const Rect2 &p_clip_rect, Rect2 p_global_rect, const Color &modulate, int p_z, RendererCanvasCull::Item *p_material_owner, bool p_use_canvas_group, RendererCanvasRender::Item *r_canvas_group_from); private: - void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr); - void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask); + void _render_canvas_item_tree(RID p_to_render_target, Canvas::ChildItem *p_child_items, int p_child_item_count, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RendererCanvasRender::Light *p_lights, RendererCanvasRender::Light *p_directional_lights, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, uint32_t p_canvas_cull_mask, RenderingMethod::RenderInfo *r_render_info = nullptr); + void _cull_canvas_item(Item *p_canvas_item, const Transform2D &p_parent_xform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RendererCanvasRender::Item **r_z_list, RendererCanvasRender::Item **r_z_last_list, Item *p_canvas_clip, Item *p_material_owner, bool p_allow_y_sort, uint32_t p_canvas_cull_mask, const Point2 &p_repeat_size, int p_repeat_times); static constexpr int z_range = RS::CANVAS_ITEM_Z_MAX - RS::CANVAS_ITEM_Z_MIN + 1; @@ -204,6 +204,7 @@ public: void canvas_initialize(RID p_rid); void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring); + void canvas_set_item_repeat(RID p_item, const Point2 &p_repeat_size, int p_repeat_times); void canvas_set_modulate(RID p_canvas, const Color &p_color); void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale); void canvas_set_disable_scale(bool p_disable); @@ -270,6 +271,10 @@ public: void canvas_item_set_debug_redraw(bool p_enabled); bool canvas_item_get_debug_redraw() const; + void canvas_item_set_interpolated(RID p_item, bool p_interpolated); + void canvas_item_reset_physics_interpolation(RID p_item); + void canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform); + RID canvas_light_allocate(); void canvas_light_initialize(RID p_rid); @@ -296,6 +301,10 @@ public: void canvas_light_set_shadow_color(RID p_light, const Color &p_color); void canvas_light_set_shadow_smooth(RID p_light, float p_smooth); + void canvas_light_set_interpolated(RID p_light, bool p_interpolated); + void canvas_light_reset_physics_interpolation(RID p_light); + void canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform); + RID canvas_light_occluder_allocate(); void canvas_light_occluder_initialize(RID p_rid); @@ -306,6 +315,10 @@ public: void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform); void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask); + void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated); + void canvas_light_occluder_reset_physics_interpolation(RID p_occluder); + void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform); + RID canvas_occluder_polygon_allocate(); void canvas_occluder_polygon_initialize(RID p_rid); @@ -335,6 +348,32 @@ public: void finalize(); + /* INTERPOLATION */ + + void tick(); + void update_interpolation_tick(bool p_process = true); + void set_physics_interpolation_enabled(bool p_enabled) { _interpolation_data.interpolation_enabled = p_enabled; } + + struct InterpolationData { + void notify_free_canvas_item(RID p_rid, RendererCanvasCull::Item &r_canvas_item); + void notify_free_canvas_light(RID p_rid, RendererCanvasRender::Light &r_canvas_light); + void notify_free_canvas_light_occluder(RID p_rid, RendererCanvasRender::LightOccluderInstance &r_canvas_light_occluder); + + LocalVector<RID> canvas_item_transform_update_lists[2]; + LocalVector<RID> *canvas_item_transform_update_list_curr = &canvas_item_transform_update_lists[0]; + LocalVector<RID> *canvas_item_transform_update_list_prev = &canvas_item_transform_update_lists[1]; + + LocalVector<RID> canvas_light_transform_update_lists[2]; + LocalVector<RID> *canvas_light_transform_update_list_curr = &canvas_light_transform_update_lists[0]; + LocalVector<RID> *canvas_light_transform_update_list_prev = &canvas_light_transform_update_lists[1]; + + LocalVector<RID> canvas_light_occluder_transform_update_lists[2]; + LocalVector<RID> *canvas_light_occluder_transform_update_list_curr = &canvas_light_occluder_transform_update_lists[0]; + LocalVector<RID> *canvas_light_occluder_transform_update_list_prev = &canvas_light_occluder_transform_update_lists[1]; + + bool interpolation_enabled = false; + } _interpolation_data; + RendererCanvasCull(); ~RendererCanvasCull(); }; diff --git a/servers/rendering/renderer_canvas_render.h b/servers/rendering/renderer_canvas_render.h index 3b78df5fab..4a56548932 100644 --- a/servers/rendering/renderer_canvas_render.h +++ b/servers/rendering/renderer_canvas_render.h @@ -51,9 +51,12 @@ public: }; struct Light { - bool enabled; + bool enabled : 1; + bool on_interpolate_transform_list : 1; + bool interpolated : 1; Color color; - Transform2D xform; + Transform2D xform_curr; + Transform2D xform_prev; float height; float energy; float scale; @@ -97,6 +100,8 @@ public: Light() { version = 0; enabled = true; + on_interpolate_transform_list = false; + interpolated = true; color = Color(1, 1, 1); shadow_color = Color(0, 0, 0, 0); height = 0; @@ -307,11 +312,17 @@ public: Rect2 rect; }; - Transform2D xform; - bool clip; - bool visible; - bool behind; - bool update_when_visible; + // For interpolation we store the current local xform, + // and the previous xform from the previous tick. + Transform2D xform_curr; + Transform2D xform_prev; + + bool clip : 1; + bool visible : 1; + bool behind : 1; + bool update_when_visible : 1; + bool on_interpolate_transform_list : 1; + bool interpolated : 1; struct CanvasGroup { RS::CanvasGroupMode mode; @@ -350,6 +361,9 @@ public: ViewportRender *vp_render = nullptr; bool distance_field; bool light_masked; + bool repeat_source; + Point2 repeat_size; + int repeat_times = 1; Rect2 global_rect_cache; @@ -363,7 +377,7 @@ public: mutable double debug_redraw_time = 0; #endif - template <class T> + template <typename T> T *alloc_command() { T *command = nullptr; if (commands == nullptr) { @@ -468,6 +482,9 @@ public: z_final = 0; texture_filter = RS::CANVAS_ITEM_TEXTURE_FILTER_DEFAULT; texture_repeat = RS::CANVAS_ITEM_TEXTURE_REPEAT_DEFAULT; + repeat_source = false; + on_interpolate_transform_list = false; + interpolated = true; } virtual ~Item() { clear(); @@ -483,12 +500,15 @@ public: virtual void canvas_render_items(RID p_to_render_target, Item *p_item_list, const Color &p_modulate, Light *p_light_list, Light *p_directional_list, const Transform2D &p_canvas_transform, RS::CanvasItemTextureFilter p_default_filter, RS::CanvasItemTextureRepeat p_default_repeat, bool p_snap_2d_vertices_to_pixel, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info = nullptr) = 0; struct LightOccluderInstance { - bool enabled; + bool enabled : 1; + bool on_interpolate_transform_list : 1; + bool interpolated : 1; RID canvas; RID polygon; RID occluder; Rect2 aabb_cache; - Transform2D xform; + Transform2D xform_curr; + Transform2D xform_prev; Transform2D xform_cache; int light_mask; bool sdf_collision; @@ -498,6 +518,8 @@ public: LightOccluderInstance() { enabled = true; + on_interpolate_transform_list = false; + interpolated = false; sdf_collision = false; next = nullptr; light_mask = 1; diff --git a/servers/rendering/renderer_compositor.cpp b/servers/rendering/renderer_compositor.cpp index c36da51e50..d364de5633 100644 --- a/servers/rendering/renderer_compositor.cpp +++ b/servers/rendering/renderer_compositor.cpp @@ -49,9 +49,11 @@ bool RendererCompositor::is_xr_enabled() const { RendererCompositor::RendererCompositor() { singleton = this; +#ifndef _3D_DISABLED if (XRServer::get_xr_mode() == XRServer::XRMODE_DEFAULT) { xr_enabled = GLOBAL_GET("xr/shaders/enabled"); } else { xr_enabled = XRServer::get_xr_mode() == XRServer::XRMODE_ON; } +#endif // _3D_DISABLED } diff --git a/servers/rendering/renderer_rd/cluster_builder_rd.cpp b/servers/rendering/renderer_rd/cluster_builder_rd.cpp index e661fd9217..41df6107a8 100644 --- a/servers/rendering/renderer_rd/cluster_builder_rd.cpp +++ b/servers/rendering/renderer_rd/cluster_builder_rd.cpp @@ -62,15 +62,17 @@ ClusterBuilderSharedDataRD::ClusterBuilderSharedDataRD() { defines = "\n#define USE_ATTACHMENT\n"; } + RD::PipelineRasterizationState rasterization_state; + rasterization_state.enable_depth_clamp = true; Vector<String> versions; versions.push_back(""); cluster_render.cluster_render_shader.initialize(versions, defines); cluster_render.shader_version = cluster_render.cluster_render_shader.version_create(); cluster_render.shader = cluster_render.cluster_render_shader.version_get_shader(cluster_render.shader_version, 0); - cluster_render.shader_pipelines[ClusterRender::PIPELINE_NORMAL] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, fb_format, vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); + cluster_render.shader_pipelines[ClusterRender::PIPELINE_NORMAL] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, fb_format, vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rasterization_state, RD::PipelineMultisampleState(), RD::PipelineDepthStencilState(), blend_state, 0); RD::PipelineMultisampleState ms; ms.sample_count = RD::TEXTURE_SAMPLES_4; - cluster_render.shader_pipelines[ClusterRender::PIPELINE_MSAA] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, fb_format, vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, RD::PipelineRasterizationState(), ms, RD::PipelineDepthStencilState(), blend_state, 0); + cluster_render.shader_pipelines[ClusterRender::PIPELINE_MSAA] = RD::get_singleton()->render_pipeline_create(cluster_render.shader, fb_format, vertex_format, RD::RENDER_PRIMITIVE_TRIANGLES, rasterization_state, ms, RD::PipelineDepthStencilState(), blend_state, 0); } { Vector<String> versions; diff --git a/servers/rendering/renderer_rd/effects/copy_effects.cpp b/servers/rendering/renderer_rd/effects/copy_effects.cpp index fd6409d6bf..1568867663 100644 --- a/servers/rendering/renderer_rd/effects/copy_effects.cpp +++ b/servers/rendering/renderer_rd/effects/copy_effects.cpp @@ -107,8 +107,8 @@ CopyEffects::CopyEffects(bool p_prefer_raster_effects) { copy_modes.push_back("\n#define MODE_PANORAMA_TO_DP\n"); // COPY_TO_FB_COPY_PANORAMA_TO_DP copy_modes.push_back("\n#define MODE_TWO_SOURCES\n"); // COPY_TO_FB_COPY2 copy_modes.push_back("\n#define MODE_SET_COLOR\n"); // COPY_TO_FB_SET_COLOR - copy_modes.push_back("\n#define MULTIVIEW\n"); // COPY_TO_FB_MULTIVIEW - copy_modes.push_back("\n#define MULTIVIEW\n#define MODE_TWO_SOURCES\n"); // COPY_TO_FB_MULTIVIEW_WITH_DEPTH + copy_modes.push_back("\n#define USE_MULTIVIEW\n"); // COPY_TO_FB_MULTIVIEW + copy_modes.push_back("\n#define USE_MULTIVIEW\n#define MODE_TWO_SOURCES\n"); // COPY_TO_FB_MULTIVIEW_WITH_DEPTH copy_to_fb.shader.initialize(copy_modes); @@ -583,7 +583,7 @@ void CopyEffects::copy_to_fb_rect(RID p_source_rd_texture, RID p_dest_framebuffe RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, p_rect); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(p_dest_framebuffer))); RD::get_singleton()->draw_list_bind_uniform_set(draw_list, uniform_set_cache->get_cache(shader, 0, u_source_rd_texture), 0); if (p_secondary.is_valid()) { @@ -982,7 +982,7 @@ void CopyEffects::set_color_raster(RID p_dest_texture, const Color &p_color, con RID shader = copy_to_fb.shader.version_get_shader(copy_to_fb.shader_version, mode); ERR_FAIL_COND(shader.is_null()); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(dest_framebuffer, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, p_region); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, copy_to_fb.pipelines[mode].get_render_pipeline(RD::INVALID_ID, RD::get_singleton()->framebuffer_get_format(dest_framebuffer))); RD::get_singleton()->draw_list_bind_index_array(draw_list, material_storage->get_quad_index_array()); RD::get_singleton()->draw_list_set_push_constant(draw_list, ©_to_fb.push_constant, sizeof(CopyToFbPushConstant)); diff --git a/servers/rendering/renderer_rd/effects/debug_effects.cpp b/servers/rendering/renderer_rd/effects/debug_effects.cpp index a57a65fd5a..017ad41fdc 100644 --- a/servers/rendering/renderer_rd/effects/debug_effects.cpp +++ b/servers/rendering/renderer_rd/effects/debug_effects.cpp @@ -282,7 +282,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj // And draw our frustum. RD::FramebufferFormatID fb_format_id = RD::get_singleton()->framebuffer_get_format(p_dest_fb); - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect); RID pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); @@ -326,7 +326,7 @@ void DebugEffects::draw_shadow_frustum(RID p_light, const Projection &p_cam_proj rect.size.x *= atlas_rect_norm.size.x; rect.size.y *= atlas_rect_norm.size.y; - draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, rect); + draw_list = RD::get_singleton()->draw_list_begin(p_dest_fb, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_LOAD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, rect); pipeline = shadow_frustum.pipelines[SFP_TRANSPARENT].get_render_pipeline(frustum.vertex_format, fb_format_id); RD::get_singleton()->draw_list_bind_render_pipeline(draw_list, pipeline); diff --git a/servers/rendering/renderer_rd/effects/fsr2.cpp b/servers/rendering/renderer_rd/effects/fsr2.cpp index bebbf51d51..925352a7d1 100644 --- a/servers/rendering/renderer_rd/effects/fsr2.cpp +++ b/servers/rendering/renderer_rd/effects/fsr2.cpp @@ -527,6 +527,7 @@ FSR2Effect::FSR2Effect() { "\n#define FFX_GLSL 1\n" "\n#define FFX_FSR2_OPTION_LOW_RESOLUTION_MOTION_VECTORS 1\n" "\n#define FFX_FSR2_OPTION_HDR_COLOR_INPUT 1\n" + "\n#define FFX_FSR2_OPTION_INVERTED_DEPTH 1\n" "\n#define FFX_FSR2_OPTION_GODOT_REACTIVE_MASK_CLAMP 1\n" "\n#define FFX_FSR2_OPTION_GODOT_DERIVE_INVALID_MOTION_VECTORS 1\n"; @@ -808,7 +809,7 @@ FSR2Effect::~FSR2Effect() { FSR2Context *FSR2Effect::create_context(Size2i p_internal_size, Size2i p_target_size) { FSR2Context *context = memnew(RendererRD::FSR2Context); - context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE; + context->fsr_desc.flags = FFX_FSR2_ENABLE_HIGH_DYNAMIC_RANGE | FFX_FSR2_ENABLE_DEPTH_INVERTED; context->fsr_desc.maxRenderSize.width = p_internal_size.x; context->fsr_desc.maxRenderSize.height = p_internal_size.y; context->fsr_desc.displaySize.width = p_target_size.x; diff --git a/servers/rendering/renderer_rd/effects/ss_effects.cpp b/servers/rendering/renderer_rd/effects/ss_effects.cpp index bdd687d9f4..3db82c8fbd 100644 --- a/servers/rendering/renderer_rd/effects/ss_effects.cpp +++ b/servers/rendering/renderer_rd/effects/ss_effects.cpp @@ -483,8 +483,12 @@ void SSEffects::downsample_depth(Ref<RenderSceneBuffersRD> p_render_buffers, uin downsample_uniform_set = uniform_set_cache->get_cache_vec(shader, 2, u_depths); } - float depth_linearize_mul = -p_projection.columns[3][2] * 0.5; - float depth_linearize_add = p_projection.columns[2][2]; + Projection correction; + correction.set_depth_correction(false); + Projection temp = correction * p_projection; + + float depth_linearize_mul = -temp.columns[3][2]; + float depth_linearize_add = temp.columns[2][2]; if (depth_linearize_mul * depth_linearize_add < 0) { depth_linearize_add = -depth_linearize_add; } diff --git a/servers/rendering/renderer_rd/effects/tone_mapper.cpp b/servers/rendering/renderer_rd/effects/tone_mapper.cpp index ee0b6adb4d..e943071f0e 100644 --- a/servers/rendering/renderer_rd/effects/tone_mapper.cpp +++ b/servers/rendering/renderer_rd/effects/tone_mapper.cpp @@ -47,12 +47,12 @@ ToneMapper::ToneMapper() { tonemap_modes.push_back("\n#define SUBPASS\n#define USE_1D_LUT\n"); // multiview versions of our shaders - tonemap_modes.push_back("\n#define MULTIVIEW\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_1D_LUT\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n"); - tonemap_modes.push_back("\n#define MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define USE_MULTIVIEW\n"); + tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n"); + tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define USE_GLOW_FILTER_BICUBIC\n#define USE_1D_LUT\n"); + tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define SUBPASS\n"); + tonemap_modes.push_back("\n#define USE_MULTIVIEW\n#define SUBPASS\n#define USE_1D_LUT\n"); tonemap.shader.initialize(tonemap_modes); @@ -130,7 +130,7 @@ void ToneMapper::tonemapper(RID p_source_color, RID p_dst_framebuffer, const Ton tonemap.push_constant.flags |= p_settings.convert_to_srgb ? TONEMAP_FLAG_CONVERT_TO_SRGB : 0; if (p_settings.view_count > 1) { - // Use MULTIVIEW versions + // Use USE_MULTIVIEW versions mode += 6; } @@ -196,7 +196,7 @@ void ToneMapper::tonemapper(RD::DrawListID p_subpass_draw_list, RID p_source_col int mode = p_settings.use_1d_color_correction ? TONEMAP_MODE_SUBPASS_1D_LUT : TONEMAP_MODE_SUBPASS; if (p_settings.view_count > 1) { - // Use MULTIVIEW versions + // Use USE_MULTIVIEW versions mode += 6; } diff --git a/servers/rendering/renderer_rd/effects/vrs.cpp b/servers/rendering/renderer_rd/effects/vrs.cpp index 41a6b2d622..30c318fb9a 100644 --- a/servers/rendering/renderer_rd/effects/vrs.cpp +++ b/servers/rendering/renderer_rd/effects/vrs.cpp @@ -32,7 +32,10 @@ #include "../renderer_compositor_rd.h" #include "../storage_rd/texture_storage.h" #include "../uniform_set_cache_rd.h" + +#ifndef _3D_DISABLED #include "servers/xr_server.h" +#endif // _3D_DISABLED using namespace RendererRD; @@ -40,7 +43,7 @@ VRS::VRS() { { Vector<String> vrs_modes; vrs_modes.push_back("\n"); // VRS_DEFAULT - vrs_modes.push_back("\n#define MULTIVIEW\n"); // VRS_MULTIVIEW + vrs_modes.push_back("\n#define USE_MULTIVIEW\n"); // VRS_MULTIVIEW vrs_shader.shader.initialize(vrs_modes); @@ -124,6 +127,7 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) { copy_vrs(rd_texture, p_vrs_fb, layers > 1); } } +#ifndef _3D_DISABLED } else if (vrs_mode == RS::VIEWPORT_VRS_XR) { Ref<XRInterface> interface = XRServer::get_singleton()->get_primary_interface(); if (interface.is_valid()) { @@ -138,6 +142,7 @@ void VRS::update_vrs_texture(RID p_vrs_fb, RID p_render_target) { } } } +#endif // _3D_DISABLED } RD::get_singleton()->draw_command_end_label(); diff --git a/servers/rendering/renderer_rd/environment/fog.cpp b/servers/rendering/renderer_rd/environment/fog.cpp index 78ab6f3650..48537a97d9 100644 --- a/servers/rendering/renderer_rd/environment/fog.cpp +++ b/servers/rendering/renderer_rd/environment/fog.cpp @@ -509,9 +509,7 @@ Vector3i Fog::_point_get_position_in_froxel_volume(const Vector3 &p_point, float 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); + fog_position = fog_position.clamp(Vector3(), fog_size); return Vector3i(fog_position); } @@ -680,8 +678,8 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P 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)); + min = min.min(points[j]); + max = max.max(points[j]); } kernel_size = max - min; @@ -931,9 +929,10 @@ void Fog::volumetric_fog_update(const VolumetricFogSettings &p_settings, const P uniforms.push_back(u); } - if (fog->copy_uniform_set.is_null()) { - 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); + if (fog->copy_uniform_set.is_valid() && RD::get_singleton()->uniform_set_is_valid(fog->copy_uniform_set)) { + RD::get_singleton()->free(fog->copy_uniform_set); } + 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); if (!gi_dependent_sets_valid) { fog->gi_dependent_sets.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_FOG), 0); diff --git a/servers/rendering/renderer_rd/environment/gi.cpp b/servers/rendering/renderer_rd/environment/gi.cpp index 6da828df45..c7752f8a86 100644 --- a/servers/rendering/renderer_rd/environment/gi.cpp +++ b/servers/rendering/renderer_rd/environment/gi.cpp @@ -3407,7 +3407,7 @@ void GI::init(SkyRD *p_sky) { RD::PipelineDepthStencilState ds; ds.enable_depth_test = true; ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + ds.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; voxel_gi_debug_shader_version_pipelines[i].setup(voxel_gi_debug_shader_version_shaders[i], RD::RENDER_PRIMITIVE_TRIANGLES, rs, RD::PipelineMultisampleState(), ds, RD::PipelineColorBlendState::create_disabled(), 0); } @@ -3575,7 +3575,7 @@ void GI::init(SkyRD *p_sky) { RD::PipelineDepthStencilState ds; ds.enable_depth_test = true; ds.enable_depth_write = true; - ds.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + ds.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; for (int i = 0; i < SDFGIShader::PROBE_DEBUG_MAX; i++) { // TODO check if version is enabled @@ -3725,6 +3725,12 @@ void GI::setup_voxel_gi_instances(RenderDataRD *p_render_data, Ref<RenderSceneBu } rbgi->uniform_set[v] = RID(); } + + if (p_render_buffers->has_custom_data(RB_SCOPE_FOG)) { + // VoxelGI instances have changed, so we need to update volumetric fog. + Ref<RendererRD::Fog::VolumetricFog> fog = p_render_buffers->get_custom_data(RB_SCOPE_FOG); + fog->sync_gi_dependent_sets_validity(true); + } } if (p_voxel_gi_instances.size() > 0) { @@ -3804,8 +3810,13 @@ void GI::process_gi(Ref<RenderSceneBuffersRD> p_render_buffers, const RID *p_nor rbgi->scene_data_ubo = RD::get_singleton()->uniform_buffer_create(sizeof(SceneData)); } + Projection correction; + correction.set_depth_correction(false); + for (uint32_t v = 0; v < p_view_count; v++) { - RendererRD::MaterialStorage::store_camera(p_projections[v].inverse(), scene_data.inv_projection[v]); + Projection temp = correction * p_projections[v]; + + RendererRD::MaterialStorage::store_camera(temp.inverse(), scene_data.inv_projection[v]); scene_data.eye_offset[v][0] = p_eye_offsets[v].x; scene_data.eye_offset[v][1] = p_eye_offsets[v].y; scene_data.eye_offset[v][2] = p_eye_offsets[v].z; diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp index 41609dc74d..27c07f23fa 100644 --- a/servers/rendering/renderer_rd/environment/sky.cpp +++ b/servers/rendering/renderer_rd/environment/sky.cpp @@ -141,7 +141,7 @@ void SkyRD::SkyShaderData::set_code(const String &p_code) { for (int i = 0; i < SKY_VERSION_MAX; i++) { RD::PipelineDepthStencilState depth_stencil_state; depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; if (scene_singleton->sky.sky_shader.shader.is_variant_enabled(i)) { RID shader_variant = scene_singleton->sky.sky_shader.shader.version_get_shader(version, i); @@ -1174,6 +1174,7 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con } Projection correction; + correction.set_depth_correction(false, true); correction.add_jitter_offset(p_jitter); sky_scene_state.view_count = p_view_count; @@ -1184,10 +1185,12 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con for (uint32_t i = 0; i < p_view_count; i++) { Projection view_inv_projection = (correction * p_view_projections[i]).inverse(); if (p_view_count > 1) { + // Reprojection is used when we need to have things in combined space. RendererRD::MaterialStorage::store_camera(p_cam_projection * view_inv_projection, sky_scene_state.ubo.combined_reprojection[i]); } else { + // This is unused so just reset to identity. Projection ident; - RendererRD::MaterialStorage::store_camera(correction, sky_scene_state.ubo.combined_reprojection[i]); + RendererRD::MaterialStorage::store_camera(ident, sky_scene_state.ubo.combined_reprojection[i]); } RendererRD::MaterialStorage::store_camera(view_inv_projection, sky_scene_state.ubo.view_inv_projections[i]); 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 fa6e78750b..0e69ad99b8 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp @@ -546,6 +546,8 @@ void RenderForwardClustered::_render_list(RenderingDevice::DrawListID p_draw_lis VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MULTIVIEW); VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS); VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_MOTION_VECTORS); + VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_SEPARATE_SPECULAR | COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS); + VALID_FLAG_COMBINATION(COLOR_PASS_FLAG_TRANSPARENT | COLOR_PASS_FLAG_MULTIVIEW | COLOR_PASS_FLAG_MOTION_VECTORS); default: { ERR_FAIL_MSG("Invalid color pass flag combination " + itos(p_params->color_pass_flags)); } @@ -1130,6 +1132,7 @@ void RenderForwardClustered::_update_sdfgi(RenderDataRD *p_render_data) { } if (rb.is_valid() && rb->has_custom_data(RB_SCOPE_SDFGI)) { + RENDER_TIMESTAMP("Render SDFGI"); Ref<RendererRD::GI::SDFGI> sdfgi = rb->get_custom_data(RB_SCOPE_SDFGI); float exposure_normalization = 1.0; @@ -1401,7 +1404,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } } - //cube shadows are rendered in their own way + RENDER_TIMESTAMP("Render OmniLight Shadows"); + // Cube shadows are rendered in their own way. for (const int &index : p_render_data->cube_shadows) { _render_shadow_pass(p_render_data->render_shadows[index].light, p_render_data->shadow_atlas, p_render_data->render_shadows[index].pass, p_render_data->render_shadows[index].instances, camera_plane, lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, true, true, true, p_render_data->render_info, viewport_size, p_render_data->scene_data->cam_transform); } @@ -1457,6 +1461,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo // drawcalls per eye/view. It will all sync up at the barrier. if (p_use_ssao || p_use_ssil) { + RENDER_TIMESTAMP("Prepare Depth for SSAO/SSIL"); // Convert our depth buffer data to linear data in for (uint32_t v = 0; v < rb->get_view_count(); v++) { ss_effects->downsample_depth(rb, v, p_render_data->scene_data->view_projection[v]); @@ -1472,6 +1477,8 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } } + RENDER_TIMESTAMP("Pre Opaque Render"); + if (current_cluster_builder) { // Note: when rendering stereoscopic (multiview) we are using our combined frustum projection to create // our cluster data. We use reprojection in the shader to adjust for our left/right eye. @@ -1504,6 +1511,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo } if (rb_data.is_valid()) { + RENDER_TIMESTAMP("Update Volumetric Fog"); bool directional_shadows = RendererRD::LightStorage::get_singleton()->has_directional_shadows(directional_light_count); _update_volumetric_fog(rb, p_render_data->environment, p_render_data->scene_data->cam_projection, p_render_data->scene_data->cam_transform, p_render_data->scene_data->prev_cam_transform.affine_inverse(), p_render_data->shadow_atlas, directional_light_count, directional_shadows, positional_light_count, p_render_data->voxel_gi_count, *p_render_data->fog_volumes); } @@ -1615,15 +1623,16 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co gi.setup_voxel_gi_instances(p_render_data, p_render_data->render_buffers, p_render_data->scene_data->cam_transform, *p_render_data->voxel_gi_instances, p_render_data->voxel_gi_count); } else { - ERR_PRINT("No render buffer nor reflection atlas, bug"); //should never happen, will crash + ERR_PRINT("No render buffer nor reflection atlas, bug"); // Should never happen! current_cluster_builder = nullptr; + return; // No point in continuing, we'll just crash. } - if (current_cluster_builder != nullptr) { - p_render_data->cluster_buffer = current_cluster_builder->get_cluster_buffer(); - p_render_data->cluster_size = current_cluster_builder->get_cluster_size(); - p_render_data->cluster_max_elements = current_cluster_builder->get_max_cluster_elements(); - } + ERR_FAIL_NULL(current_cluster_builder); + + p_render_data->cluster_buffer = current_cluster_builder->get_cluster_buffer(); + p_render_data->cluster_size = current_cluster_builder->get_cluster_size(); + p_render_data->cluster_max_elements = current_cluster_builder->get_max_cluster_elements(); _update_vrs(rb); @@ -1964,6 +1973,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co WARN_PRINT_ONCE("Pre opaque rendering effects can't access resolved depth buffers."); } + RENDER_TIMESTAMP("Process Pre Opaque Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_OPAQUE, p_render_data); } @@ -1975,6 +1985,8 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } _pre_opaque_render(p_render_data, using_ssao, using_ssil, using_sdfgi || using_voxelgi, normal_roughness_views, rb_data.is_valid() && rb_data->has_voxelgi() ? rb_data->get_voxelgi() : RID()); + RENDER_TIMESTAMP("Render Opaque Pass"); + RD::get_singleton()->draw_command_begin_label("Render Opaque Pass"); p_render_data->scene_data->directional_light_count = p_render_data->directional_light_count; @@ -1985,8 +1997,6 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co _setup_environment(p_render_data, is_reflection_probe, screen_size, !is_reflection_probe, p_default_bg_color, true, using_motion_pass); - RENDER_TIMESTAMP("Render Opaque Pass"); - RID rp_uniform_set = _setup_render_pass_uniform_set(RENDER_LIST_OPAQUE, p_render_data, radiance_texture, samplers, true); { @@ -2011,7 +2021,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co uint32_t opaque_color_pass_flags = using_motion_pass ? (color_pass_flags & ~COLOR_PASS_FLAG_MOTION_VECTORS) : color_pass_flags; RID opaque_framebuffer = using_motion_pass ? rb_data->get_color_pass_fb(opaque_color_pass_flags) : color_framebuffer; RenderListParameters render_list_params(render_list[RENDER_LIST_OPAQUE].elements.ptr(), render_list[RENDER_LIST_OPAQUE].element_info.ptr(), render_list[RENDER_LIST_OPAQUE].elements.size(), reverse_cull, PASS_MODE_COLOR, opaque_color_pass_flags, rb_data.is_null(), p_render_data->directional_light_soft_shadows, rp_uniform_set, get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_WIREFRAME, Vector2(), p_render_data->scene_data->lod_distance_multiplier, p_render_data->scene_data->screen_mesh_lod_threshold, p_render_data->scene_data->view_count, 0, spec_constant_base_flags); - _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0); + _render_list_with_draw_list(&render_list_params, opaque_framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, depth_pre_pass ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0); } RD::get_singleton()->draw_command_end_label(); @@ -2050,6 +2060,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } + RENDER_TIMESTAMP("Process Post Opaque Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_OPAQUE, p_render_data); } @@ -2110,6 +2121,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } { + RENDER_TIMESTAMP("Process Post Sky Compositor Effects"); // Don't need to check for depth or color resolve here, we've already triggered it. _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_SKY, p_render_data); } @@ -2187,6 +2199,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co } } + RENDER_TIMESTAMP("Process Pre Transparent Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_PRE_TRANSPARENT, p_render_data); } @@ -2231,6 +2244,7 @@ void RenderForwardClustered::_render_scene(RenderDataRD *p_render_data, const Co RD::get_singleton()->draw_command_end_label(); { + RENDER_TIMESTAMP("Process Post Transparent Compositor Effects"); _process_compositor_effects(RS::COMPOSITOR_EFFECT_CALLBACK_TYPE_POST_TRANSPARENT, p_render_data); } @@ -2626,7 +2640,7 @@ void RenderForwardClustered::_render_shadow_end() { for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, 0, true, false, shadow_pass.rp_uniform_set, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from); - _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect); + _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect); } RD::get_singleton()->draw_command_end_label(); @@ -2726,7 +2740,7 @@ void RenderForwardClustered::_render_material(const Transform3D &p_cam_transform Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } @@ -2776,7 +2790,7 @@ void RenderForwardClustered::_render_uv2(const PagedArray<RenderGeometryInstance Color(0, 0, 0, 0), Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); const int uv_offset_count = 9; static const Vector2 uv_offsets[uv_offset_count] = { @@ -2882,7 +2896,7 @@ void RenderForwardClustered::_render_sdfgi(Ref<RenderSceneBuffersRD> p_render_bu } RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].element_info.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), true, pass_mode, 0, true, false, rp_uniform_set, false); - _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 1.0, 0, Rect2()); + _render_list_with_draw_list(&render_list_params, E->value, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, Vector<Color>(), 0.0, 0, Rect2()); } RD::get_singleton()->draw_command_end_label(); @@ -4262,7 +4276,7 @@ RenderForwardClustered::RenderForwardClustered() { sampler.mag_filter = RD::SAMPLER_FILTER_NEAREST; sampler.min_filter = RD::SAMPLER_FILTER_NEAREST; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } 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 12af8822b4..1f12d92754 100644 --- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h +++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.h @@ -379,7 +379,7 @@ class RenderForwardClustered : public RendererSceneRenderRD { template <PassMode p_pass_mode, uint32_t p_color_pass_flags = 0> _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); void _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); - void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); void _update_instance_data_buffer(RenderListType p_render_list); void _fill_instance_data(RenderListType p_render_list, int *p_render_info = nullptr, uint32_t p_offset = 0, int32_t p_max_elements = -1, bool p_update_buffer = true); 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 55c6c420eb..209fabeddf 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 @@ -260,7 +260,7 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) { if (depth_test != DEPTH_TEST_DISABLED) { depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; } bool depth_pre_pass_enabled = bool(GLOBAL_GET("rendering/driver/depth_prepass/enable")); @@ -737,7 +737,7 @@ void SceneShaderForwardClustered::init(const String p_defines) { default_shader = material_storage->shader_allocate(); material_storage->shader_initialize(default_shader); material_storage->shader_set_code(default_shader, R"( -// Default 3D material shader (clustered). +// Default 3D material shader (Forward+). shader_type spatial; @@ -768,11 +768,11 @@ void fragment() { material_storage->shader_initialize(overdraw_material_shader); // Use relatively low opacity so that more "layers" of overlapping objects can be distinguished. material_storage->shader_set_code(overdraw_material_shader, R"( -// 3D editor Overdraw debug draw mode shader (clustered). +// 3D editor Overdraw debug draw mode shader (Forward+). shader_type spatial; -render_mode blend_add, unshaded; +render_mode blend_add, unshaded, fog_disabled; void fragment() { ALBEDO = vec3(0.4, 0.8, 0.8); @@ -792,11 +792,11 @@ void fragment() { debug_shadow_splits_material_shader = material_storage->shader_allocate(); material_storage->shader_initialize(debug_shadow_splits_material_shader); material_storage->shader_set_code(debug_shadow_splits_material_shader, R"( -// 3D debug shadow splits mode shader(mobile). +// 3D debug shadow splits mode shader (Forward+). shader_type spatial; -render_mode debug_shadow_splits; +render_mode debug_shadow_splits, fog_disabled; void fragment() { ALBEDO = vec3(1.0, 1.0, 1.0); @@ -827,7 +827,7 @@ void fragment() { sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } } 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 ac93aca6bb..48c9cda253 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp @@ -777,7 +777,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) { // can't do blit subpass because we're scaling using_subpass_post_process = false; - } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) { + } else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes) || environment_get_background(p_render_data->environment) == RS::ENV_BG_CANVAS)) { // can't do blit subpass because we're using post processes using_subpass_post_process = false; } @@ -984,7 +984,7 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color } } - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 1.0, 0); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(framebuffer, load_color ? RD::INITIAL_ACTION_LOAD : RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, c, 0.0, 0); RD::FramebufferFormatID fb_format = RD::get_singleton()->framebuffer_get_format(framebuffer); if (copy_canvas) { @@ -1385,7 +1385,7 @@ void RenderForwardMobile::_render_shadow_end() { for (SceneState::ShadowPass &shadow_pass : scene_state.shadow_passes) { RenderListParameters render_list_parameters(render_list[RENDER_LIST_SECONDARY].elements.ptr() + shadow_pass.element_from, render_list[RENDER_LIST_SECONDARY].element_info.ptr() + shadow_pass.element_from, shadow_pass.element_count, shadow_pass.flip_cull, shadow_pass.pass_mode, shadow_pass.rp_uniform_set, 0, false, Vector2(), shadow_pass.lod_distance_multiplier, shadow_pass.screen_mesh_lod_threshold, 1, shadow_pass.element_from); - _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 1.0, 0, shadow_pass.rect); + _render_list_with_draw_list(&render_list_parameters, shadow_pass.framebuffer, RD::INITIAL_ACTION_DISCARD, RD::FINAL_ACTION_DISCARD, shadow_pass.initial_depth_action, RD::FINAL_ACTION_STORE, Vector<Color>(), 0.0, 0, shadow_pass.rect); } RD::get_singleton()->draw_command_end_label(); @@ -1437,7 +1437,7 @@ void RenderForwardMobile::_render_material(const Transform3D &p_cam_transform, c Color(0, 0, 0, 0), Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); _render_list(draw_list, RD::get_singleton()->framebuffer_get_format(p_framebuffer), &render_list_params, 0, render_list_params.element_count); RD::get_singleton()->draw_list_end(); } @@ -1483,7 +1483,7 @@ void RenderForwardMobile::_render_uv2(const PagedArray<RenderGeometryInstance *> Color(0, 0, 0, 0) }; - RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 1.0, 0, p_region); + RD::DrawListID draw_list = RD::get_singleton()->draw_list_begin(p_framebuffer, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_STORE, clear, 0.0, 0, p_region); const int uv_offset_count = 9; static const Vector2 uv_offsets[uv_offset_count] = { @@ -2835,6 +2835,11 @@ RenderForwardMobile::~RenderForwardMobile() { for (const RID &rid : scene_state.uniform_buffers) { RD::get_singleton()->free(rid); } + for (uint32_t i = 0; i < RENDER_LIST_MAX; i++) { + if (scene_state.instance_buffer[i].is_valid()) { + RD::get_singleton()->free(scene_state.instance_buffer[i]); + } + } RD::get_singleton()->free(scene_state.lightmap_buffer); RD::get_singleton()->free(scene_state.lightmap_capture_buffer); memdelete_arr(scene_state.lightmap_captures); 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 5c02204627..f29503e5ec 100644 --- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h +++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.h @@ -350,7 +350,7 @@ private: template <PassMode p_pass_mode> _FORCE_INLINE_ void _render_list_template(RenderingDevice::DrawListID p_draw_list, RenderingDevice::FramebufferFormatID p_framebuffer_Format, RenderListParameters *p_params, uint32_t p_from_element, uint32_t p_to_element); void _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); - void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + void _render_list_with_draw_list(RenderListParameters *p_params, RID p_framebuffer, RD::InitialAction p_initial_color_action, RD::FinalAction p_final_color_action, RD::InitialAction p_initial_depth_action, RD::FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); RenderList render_list[RENDER_LIST_MAX]; 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 3592ee2f6d..a2f112669c 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 @@ -271,7 +271,7 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) { if (depth_test != DEPTH_TEST_DISABLED) { depth_stencil_state.enable_depth_test = true; - depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_LESS_OR_EQUAL; + depth_stencil_state.depth_compare_operator = RD::COMPARE_OP_GREATER_OR_EQUAL; depth_stencil_state.enable_depth_write = depth_draw != DEPTH_DRAW_DISABLED ? true : false; } @@ -641,7 +641,7 @@ void SceneShaderForwardMobile::init(const String p_defines) { default_shader = material_storage->shader_allocate(); material_storage->shader_initialize(default_shader); material_storage->shader_set_code(default_shader, R"( -// Default 3D material shader (mobile). +// Default 3D material shader (Mobile). shader_type spatial; @@ -671,11 +671,11 @@ void fragment() { material_storage->shader_initialize(overdraw_material_shader); // Use relatively low opacity so that more "layers" of overlapping objects can be distinguished. material_storage->shader_set_code(overdraw_material_shader, R"( -// 3D editor Overdraw debug draw mode shader (mobile). +// 3D editor Overdraw debug draw mode shader (Mobile). shader_type spatial; -render_mode blend_add, unshaded; +render_mode blend_add, unshaded, fog_disabled; void fragment() { ALBEDO = vec3(0.4, 0.8, 0.8); @@ -696,11 +696,11 @@ void fragment() { material_storage->shader_initialize(debug_shadow_splits_material_shader); // Use relatively low opacity so that more "layers" of overlapping objects can be distinguished. material_storage->shader_set_code(debug_shadow_splits_material_shader, R"( -// 3D debug shadow splits mode shader(mobile). +// 3D debug shadow splits mode shader (Mobile). shader_type spatial; -render_mode debug_shadow_splits; +render_mode debug_shadow_splits, fog_disabled; void fragment() { ALBEDO = vec3(1.0, 1.0, 1.0); @@ -731,7 +731,7 @@ void fragment() { sampler.mag_filter = RD::SAMPLER_FILTER_LINEAR; sampler.min_filter = RD::SAMPLER_FILTER_LINEAR; sampler.enable_compare = true; - sampler.compare_op = RD::COMPARE_OP_LESS; + sampler.compare_op = RD::COMPARE_OP_GREATER; shadow_sampler = RD::get_singleton()->sampler_create(sampler); } } diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp index 00604d0d4b..6f56711151 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp @@ -34,6 +34,7 @@ #include "core/math/geometry_2d.h" #include "core/math/math_defs.h" #include "core/math/math_funcs.h" +#include "core/math/transform_interpolator.h" #include "renderer_compositor_rd.h" #include "servers/rendering/renderer_rd/storage_rd/material_storage.h" #include "servers/rendering/renderer_rd/storage_rd/particles_storage.h" @@ -406,7 +407,7 @@ _FORCE_INLINE_ static uint32_t _indices_to_primitives(RS::PrimitiveType p_primit return (p_indices - subtractor[p_primitive]) / divisor[p_primitive]; } -void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info) { +void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RD::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used, const Point2 &p_offset, RenderingMethod::RenderInfo *r_render_info) { //create an empty push constant RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton(); RendererRD::MeshStorage *mesh_storage = RendererRD::MeshStorage::get_singleton(); @@ -425,6 +426,11 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend PushConstant push_constant; Transform2D base_transform = p_canvas_transform_inverse * p_item->final_transform; + + if (p_offset.x || p_offset.y) { + base_transform *= Transform2D(0, p_offset / p_item->xform_curr.get_scale()); // TODO: Interpolate or explain why not needed. + } + Transform2D draw_transform; _update_transform_2d_to_mat2x3(base_transform, push_constant.world); @@ -1240,7 +1246,23 @@ void RendererCanvasRenderRD::_render_items(RID p_to_render_target, int p_item_co } } - _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants, r_sdf_used, r_render_info); + if (!ci->repeat_size.x && !ci->repeat_size.y) { + _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants, r_sdf_used, Point2(), r_render_info); + } else { + Point2 start_pos = ci->repeat_size * -(ci->repeat_times / 2); + Point2 end_pos = ci->repeat_size * ci->repeat_times + ci->repeat_size + start_pos; + Point2 pos = start_pos; + + do { + do { + _render_item(draw_list, p_to_render_target, ci, fb_format, canvas_transform_inverse, current_clip, p_lights, pipeline_variants, r_sdf_used, pos, r_render_info); + pos.y += ci->repeat_size.y; + } while (pos.y < end_pos.y); + + pos.x += ci->repeat_size.x; + pos.y = start_pos.y; + } while (pos.x < end_pos.x); + } prev_material = material; } @@ -1345,7 +1367,15 @@ void RendererCanvasRenderRD::canvas_render_items(RID p_to_render_target, Item *p ERR_CONTINUE(!clight); } - Vector2 canvas_light_pos = p_canvas_transform.xform(l->xform.get_origin()); //convert light position to canvas coordinates, as all computation is done in canvas coords to avoid precision loss + Transform2D final_xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !l->interpolated) { + final_xform = l->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(l->xform_prev, l->xform_curr, final_xform, f); + } + // Convert light position to canvas coordinates, as all computation is done in canvas coordinates to avoid precision loss. + Vector2 canvas_light_pos = p_canvas_transform.xform(final_xform.get_origin()); state.light_uniforms[index].position[0] = canvas_light_pos.x; state.light_uniforms[index].position[1] = canvas_light_pos.y; diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h index 6da3774fc2..c7c5d34314 100644 --- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h +++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h @@ -424,7 +424,7 @@ class RendererCanvasRenderRD : public RendererCanvasRender { double debug_redraw_time = 1.0; inline void _bind_canvas_texture(RD::DrawListID p_draw_list, RID p_texture, RS::CanvasItemTextureFilter p_base_filter, RS::CanvasItemTextureRepeat p_base_repeat, RID &r_last_texture, PushConstant &push_constant, Size2 &r_texpixel_size, bool p_texture_is_data = false); //recursive, so regular inline used instead. - void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used, RenderingMethod::RenderInfo *r_render_info = nullptr); + void _render_item(RenderingDevice::DrawListID p_draw_list, RID p_render_target, const Item *p_item, RenderingDevice::FramebufferFormatID p_framebuffer_format, const Transform2D &p_canvas_transform_inverse, Item *¤t_clip, Light *p_lights, PipelineVariants *p_pipeline_variants, bool &r_sdf_used, const Point2 &p_offset, RenderingMethod::RenderInfo *r_render_info = nullptr); void _render_items(RID p_to_render_target, int p_item_count, const Transform2D &p_canvas_transform_inverse, Light *p_lights, bool &r_sdf_used, bool p_to_backbuffer = false, RenderingMethod::RenderInfo *r_render_info = nullptr); _FORCE_INLINE_ void _update_transform_2d_to_mat2x4(const Transform2D &p_transform, float *p_mat2x4); diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp index 62ecec3991..e61bb9eae8 100644 --- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp +++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp @@ -1153,12 +1153,19 @@ void RendererSceneRenderRD::render_scene(const Ref<RenderSceneBuffers> &p_render PagedArray<RID> empty; - if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED) { + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED || get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { render_data.lights = ∅ render_data.reflection_probes = ∅ render_data.voxel_gi_instances = ∅ } + if (get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_UNSHADED || + get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_OVERDRAW || + get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_LIGHTING || + get_debug_draw_mode() == RS::VIEWPORT_DEBUG_DRAW_PSSM_SPLITS) { + render_data.decals = ∅ + } + Color clear_color; if (p_render_buffers.is_valid() && p_reflection_probe.is_null()) { clear_color = texture_storage->render_target_get_clear_request_color(rb->get_render_target()); diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl index fe770ac065..48c1b0a3f6 100644 --- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof.glsl @@ -32,9 +32,9 @@ layout(set = 1, binding = 0) uniform sampler2D source_bokeh; float get_depth_at_pos(vec2 uv) { float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + depth = -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); } return depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl index 947aa793d9..2010b58474 100644 --- a/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/bokeh_dof_raster.glsl @@ -53,9 +53,9 @@ layout(set = 2, binding = 0) uniform sampler2D original_weight; float get_depth_at_pos(vec2 uv) { float depth = textureLod(source_depth, uv, 0.0).x * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + depth = -(depth * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); + depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); } return depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl index 1b065a8dd3..7192e596eb 100644 --- a/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/copy_to_fb.glsl @@ -4,14 +4,14 @@ #VERSION_DEFINES -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW #ifdef has_VK_KHR_multiview #extension GL_EXT_multiview : enable #define ViewIndex gl_ViewIndex #else // has_VK_KHR_multiview #define ViewIndex 0 #endif // has_VK_KHR_multiview -#endif //MULTIVIEW +#endif //USE_MULTIVIEW #define FLAG_FLIP_Y (1 << 0) #define FLAG_USE_SECTION (1 << 1) @@ -22,7 +22,7 @@ #define FLAG_LINEAR (1 << 6) #define FLAG_NORMAL (1 << 7) -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW layout(location = 0) out vec3 uv_interp; #else layout(location = 0) out vec2 uv_interp; @@ -41,7 +41,7 @@ params; 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_interp.xy = base_arr[gl_VertexIndex]; -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW uv_interp.z = ViewIndex; #endif vec2 vpos = uv_interp.xy; @@ -62,14 +62,14 @@ void main() { #VERSION_DEFINES -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW #ifdef has_VK_KHR_multiview #extension GL_EXT_multiview : enable #define ViewIndex gl_ViewIndex #else // has_VK_KHR_multiview #define ViewIndex 0 #endif // has_VK_KHR_multiview -#endif //MULTIVIEW +#endif //USE_MULTIVIEW #define FLAG_FLIP_Y (1 << 0) #define FLAG_USE_SECTION (1 << 1) @@ -91,24 +91,24 @@ layout(push_constant, std430) uniform Params { params; #ifndef MODE_SET_COLOR -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW layout(location = 0) in vec3 uv_interp; #else layout(location = 0) in vec2 uv_interp; #endif -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW layout(set = 0, binding = 0) uniform sampler2DArray source_color; #ifdef MODE_TWO_SOURCES layout(set = 1, binding = 0) uniform sampler2DArray source_depth; layout(location = 1) out float depth; #endif /* MODE_TWO_SOURCES */ -#else /* MULTIVIEW */ +#else /* USE_MULTIVIEW */ layout(set = 0, binding = 0) uniform sampler2D source_color; #ifdef MODE_TWO_SOURCES layout(set = 1, binding = 0) uniform sampler2D source_color2; #endif /* MODE_TWO_SOURCES */ -#endif /* MULTIVIEW */ +#endif /* USE_MULTIVIEW */ #endif /* !SET_COLOR */ layout(location = 0) out vec4 frag_color; @@ -129,7 +129,7 @@ void main() { frag_color = params.color; #else -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW vec3 uv = uv_interp; #else vec2 uv = uv_interp; @@ -165,19 +165,19 @@ void main() { } #endif /* MODE_PANORAMA_TO_DP */ -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW vec4 color = textureLod(source_color, uv, 0.0); #ifdef MODE_TWO_SOURCES // In multiview our 2nd input will be our depth map depth = textureLod(source_depth, uv, 0.0).r; #endif /* MODE_TWO_SOURCES */ -#else /* MULTIVIEW */ +#else /* USE_MULTIVIEW */ vec4 color = textureLod(source_color, uv, 0.0); #ifdef MODE_TWO_SOURCES color += textureLod(source_color2, uv, 0.0); #endif /* MODE_TWO_SOURCES */ -#endif /* MULTIVIEW */ +#endif /* USE_MULTIVIEW */ if (bool(params.flags & FLAG_FORCE_LUMINANCE)) { color.rgb = vec3(max(max(color.r, color.g), color.b)); diff --git a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl index e77d0de719..3fb93dda35 100644 --- a/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/cube_to_dp.glsl @@ -77,8 +77,8 @@ void main() { float depth_fix = 1.0 / dot(normal, unorm); depth = 2.0 * depth - 1.0; - float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - depth * (params.z_far - params.z_near)); - depth = (linear_depth * depth_fix) / params.z_far; - + float linear_depth = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + depth * (params.z_far - params.z_near)); + // linear_depth equal to view space depth + depth = (params.z_far - linear_depth * depth_fix) / params.z_far; gl_FragDepth = depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl index 51caa67d3c..d9e21b8cd1 100644 --- a/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/screen_space_reflection_scale.glsl @@ -98,9 +98,9 @@ void main() { // unproject our Z value so we can use it directly. depth = depth * 2.0 - 1.0; if (params.orthogonal) { - depth = ((depth + (params.camera_z_far + params.camera_z_near) / (params.camera_z_far - params.camera_z_near)) * (params.camera_z_far - params.camera_z_near)) / 2.0; + depth = -(depth * (params.camera_z_far - params.camera_z_near) - (params.camera_z_far + params.camera_z_near)) / 2.0; } else { - depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near - depth * (params.camera_z_far - params.camera_z_near)); + depth = 2.0 * params.camera_z_near * params.camera_z_far / (params.camera_z_far + params.camera_z_near + depth * (params.camera_z_far - params.camera_z_near)); } depth = -depth; } diff --git a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl index 33ec991107..38eec2b61a 100644 --- a/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/tonemap.glsl @@ -4,7 +4,7 @@ #VERSION_DEFINES -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW #ifdef has_VK_KHR_multiview #extension GL_EXT_multiview : enable #endif @@ -24,27 +24,27 @@ void main() { #VERSION_DEFINES -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW #ifdef has_VK_KHR_multiview #extension GL_EXT_multiview : enable #define ViewIndex gl_ViewIndex #else // has_VK_KHR_multiview #define ViewIndex 0 #endif // has_VK_KHR_multiview -#endif //MULTIVIEW +#endif //USE_MULTIVIEW layout(location = 0) in vec2 uv_interp; #ifdef SUBPASS layout(input_attachment_index = 0, set = 0, binding = 0) uniform subpassInput input_color; -#elif defined(MULTIVIEW) +#elif defined(USE_MULTIVIEW) layout(set = 0, binding = 0) uniform sampler2DArray source_color; #else layout(set = 0, binding = 0) uniform sampler2D source_color; #endif layout(set = 1, binding = 0) uniform sampler2D source_auto_exposure; -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW layout(set = 2, binding = 0) uniform sampler2DArray source_glow; #else layout(set = 2, binding = 0) uniform sampler2D source_glow; @@ -125,7 +125,7 @@ float h1(float a) { return 1.0f + w3(a) / (w2(a) + w3(a)); } -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW vec4 texture2D_bicubic(sampler2DArray tex, vec2 uv, int p_lod) { float lod = float(p_lod); vec2 tex_size = vec2(params.glow_texture_size >> p_lod); @@ -153,7 +153,7 @@ vec4 texture2D_bicubic(sampler2DArray tex, vec2 uv, int p_lod) { } #define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) -#else // MULTIVIEW +#else // USE_MULTIVIEW vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { float lod = float(p_lod); @@ -182,15 +182,15 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { } #define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) -#endif // !MULTIVIEW +#endif // !USE_MULTIVIEW #else // USE_GLOW_FILTER_BICUBIC -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW #define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, vec3(m_uv, ViewIndex), float(m_lod)) -#else // MULTIVIEW +#else // USE_MULTIVIEW #define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod)) -#endif // !MULTIVIEW +#endif // !USE_MULTIVIEW #endif // !USE_GLOW_FILTER_BICUBIC @@ -273,11 +273,11 @@ vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always o } } -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW vec3 gather_glow(sampler2DArray tex, vec2 uv) { // sample all selected glow levels, view is added to uv later #else vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels -#endif // defined(MULTIVIEW) +#endif // defined(USE_MULTIVIEW) vec3 glow = vec3(0.0f); if (params.glow_levels[0] > 0.0001) { @@ -364,7 +364,7 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { const float FXAA_REDUCE_MUL = (1.0 / 8.0); const float FXAA_SPAN_MAX = 8.0; -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW vec3 rgbNW = textureLod(source_color, vec3(uv_interp + vec2(-0.5, -0.5) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; vec3 rgbNE = textureLod(source_color, vec3(uv_interp + vec2(0.5, -0.5) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; vec3 rgbSW = textureLod(source_color, vec3(uv_interp + vec2(-0.5, 0.5) * params.pixel_size, ViewIndex), 0.0).xyz * exposure * params.luminance_multiplier; @@ -399,7 +399,7 @@ vec3 do_fxaa(vec3 color, float exposure, vec2 uv_interp) { dir * rcpDirMin)) * params.pixel_size; -#ifdef MULTIVIEW +#ifdef USE_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; vec3 rgbB = rgbA * 0.5 + 0.25 * exposure * (textureLod(source_color, vec3(uv_interp + dir * -0.5, ViewIndex), 0.0).xyz + textureLod(source_color, vec3(uv_interp + dir * 0.5, ViewIndex), 0.0).xyz) * params.luminance_multiplier; #else @@ -430,9 +430,9 @@ vec3 screen_space_dither(vec2 frag_coord) { void main() { #ifdef SUBPASS - // SUBPASS and MULTIVIEW can be combined but in that case we're already reading from the correct layer + // SUBPASS and USE_MULTIVIEW can be combined but in that case we're already reading from the correct layer vec4 color = subpassLoad(input_color); -#elif defined(MULTIVIEW) +#elif defined(USE_MULTIVIEW) vec4 color = textureLod(source_color, vec3(uv_interp, ViewIndex), 0.0f); #else vec4 color = textureLod(source_color, uv_interp, 0.0f); diff --git a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl index d3d39a8b92..23b0373eef 100644 --- a/servers/rendering/renderer_rd/shaders/effects/vrs.glsl +++ b/servers/rendering/renderer_rd/shaders/effects/vrs.glsl @@ -4,16 +4,16 @@ #VERSION_DEFINES -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW #ifdef has_VK_KHR_multiview #extension GL_EXT_multiview : enable #define ViewIndex gl_ViewIndex #else // has_VK_KHR_multiview #define ViewIndex 0 #endif // has_VK_KHR_multiview -#endif //MULTIVIEW +#endif //USE_MULTIVIEW -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW layout(location = 0) out vec3 uv_interp; #else layout(location = 0) out vec2 uv_interp; @@ -23,7 +23,7 @@ void main() { vec2 base_arr[3] = vec2[](vec2(-1.0, -1.0), vec2(-1.0, 3.0), vec2(3.0, -1.0)); gl_Position = vec4(base_arr[gl_VertexIndex], 0.0, 1.0); uv_interp.xy = clamp(gl_Position.xy, vec2(0.0, 0.0), vec2(1.0, 1.0)) * 2.0; // saturate(x) * 2.0 -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW uv_interp.z = ViewIndex; #endif } @@ -34,36 +34,36 @@ void main() { #VERSION_DEFINES -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW #ifdef has_VK_KHR_multiview #extension GL_EXT_multiview : enable #define ViewIndex gl_ViewIndex #else // has_VK_KHR_multiview #define ViewIndex 0 #endif // has_VK_KHR_multiview -#endif //MULTIVIEW +#endif //USE_MULTIVIEW -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW layout(location = 0) in vec3 uv_interp; layout(set = 0, binding = 0) uniform sampler2DArray source_color; -#else /* MULTIVIEW */ +#else /* USE_MULTIVIEW */ layout(location = 0) in vec2 uv_interp; layout(set = 0, binding = 0) uniform sampler2D source_color; -#endif /* MULTIVIEW */ +#endif /* USE_MULTIVIEW */ layout(location = 0) out uint frag_color; void main() { -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW vec3 uv = uv_interp; #else vec2 uv = uv_interp; #endif -#ifdef MULTIVIEW +#ifdef USE_MULTIVIEW vec4 color = textureLod(source_color, uv, 0.0); frag_color = uint(color.r * 255.0); -#else /* MULTIVIEW */ +#else /* USE_MULTIVIEW */ vec4 color = textureLod(source_color, uv, 0.0); // for user supplied VRS map we do a color mapping @@ -75,5 +75,5 @@ void main() { // note 1x4, 4x1, 1x8, 8x1, 2x8 and 8x2 are not supported // 4x8, 8x4 and 8x8 are only available on some GPUs -#endif /* MULTIVIEW */ +#endif /* USE_MULTIVIEW */ } diff --git a/servers/rendering/renderer_rd/shaders/environment/gi.glsl b/servers/rendering/renderer_rd/shaders/environment/gi.glsl index 80ed34cda1..480172f9dc 100644 --- a/servers/rendering/renderer_rd/shaders/environment/gi.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/gi.glsl @@ -174,9 +174,9 @@ vec3 reconstruct_position(ivec2 screen_pos) { pos.z = pos.z * 2.0 - 1.0; if (params.orthogonal) { - pos.z = ((pos.z + (params.z_far + params.z_near) / (params.z_far - params.z_near)) * (params.z_far - params.z_near)) / 2.0; + pos.z = -(pos.z * (params.z_far - params.z_near) - (params.z_far + params.z_near)) / 2.0; } else { - pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near - pos.z * (params.z_far - params.z_near)); + pos.z = 2.0 * params.z_near * params.z_far / (params.z_far + params.z_near + pos.z * (params.z_far - params.z_near)); } pos.z = -pos.z; diff --git a/servers/rendering/renderer_rd/shaders/environment/sky.glsl b/servers/rendering/renderer_rd/shaders/environment/sky.glsl index 4e5b11aed8..35457a2482 100644 --- a/servers/rendering/renderer_rd/shaders/environment/sky.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/sky.glsl @@ -25,7 +25,7 @@ params; void main() { vec2 base_arr[3] = vec2[](vec2(-1.0, -3.0), vec2(-1.0, 1.0), vec2(3.0, 1.0)); uv_interp = base_arr[gl_VertexIndex]; - gl_Position = vec4(uv_interp, 1.0, 1.0); + gl_Position = vec4(uv_interp, 0.0, 1.0); } #[fragment] @@ -158,7 +158,7 @@ vec3 interleaved_gradient_noise(vec2 pos) { vec4 volumetric_fog_process(vec2 screen_uv) { #ifdef USE_MULTIVIEW - vec4 reprojected = sky_scene_data.combined_reprojection[ViewIndex] * (vec4(screen_uv * 2.0 - 1.0, 1.0, 1.0) * sky_scene_data.z_far); + vec4 reprojected = sky_scene_data.combined_reprojection[ViewIndex] * vec4(screen_uv * 2.0 - 1.0, 0.0, 1.0); // Unproject at the far plane vec3 fog_pos = vec3(reprojected.xy / reprojected.w, 1.0) * 0.5 + 0.5; #else vec3 fog_pos = vec3(screen_uv, 1.0); @@ -187,9 +187,11 @@ void main() { vec3 cube_normal; #ifdef USE_MULTIVIEW // In multiview our projection matrices will contain positional and rotational offsets that we need to properly unproject. - vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 1.0, 1.0); + vec4 unproject = vec4(uv_interp.x, -uv_interp.y, 0.0, 1.0); // unproject at the far plane vec4 unprojected = sky_scene_data.view_inv_projections[ViewIndex] * unproject; cube_normal = unprojected.xyz / unprojected.w; + + // Unproject will give us the position between the eyes, need to re-offset cube_normal += sky_scene_data.view_eye_offsets[ViewIndex].xyz; #else cube_normal.z = -1.0; diff --git a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl index 57b9a4c320..d0cfe6a3b8 100644 --- a/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl +++ b/servers/rendering/renderer_rd/shaders/environment/volumetric_fog_process.glsl @@ -416,7 +416,7 @@ void main() { } 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 * INV_FOG_FADE); + float shadow = exp(min(0.0, (pssm_coord.z - depth)) * z_range * INV_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 @@ -519,7 +519,7 @@ void main() { float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; - shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE)); + shadow_attenuation = mix(1.0 - omni_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (pos.z - depth)) / omni_lights.data[light_index].inv_radius * INV_FOG_FADE)); } total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_pos - view_pos), normalize(view_pos)), params.phase_g) * omni_lights.data[light_index].volumetric_fog_energy; } @@ -597,7 +597,7 @@ void main() { float depth = texture(sampler2D(shadow_atlas, linear_sampler), pos.xy).r; - shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (depth - pos.z)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE)); + shadow_attenuation = mix(1.0 - spot_lights.data[light_index].shadow_opacity, 1.0, exp(min(0.0, (pos.z - depth)) / spot_lights.data[light_index].inv_radius * INV_FOG_FADE)); } total_light += light * attenuation * shadow_attenuation * henyey_greenstein(dot(normalize(light_rel_vec), normalize(view_pos)), params.phase_g) * spot_lights.data[light_index].volumetric_fog_energy; } diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl index 6eae64c04e..359d7799e5 100644 --- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl @@ -487,8 +487,8 @@ void vertex_shader(vec3 vertex_input, #ifdef MODE_RENDER_DEPTH if (scene_data.pancake_shadows) { - if (gl_Position.z <= 0.00001) { - gl_Position.z = 0.00001; + if (gl_Position.z >= 0.9999) { + gl_Position.z = 0.9999; } } #endif diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl index 259edc63a0..c26313092b 100644 --- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl +++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl @@ -475,8 +475,8 @@ void main() { #ifdef MODE_RENDER_DEPTH if (scene_data.pancake_shadows) { - if (gl_Position.z <= 0.00001) { - gl_Position.z = 0.00001; + if (gl_Position.z >= 0.9999) { + gl_Position.z = 0.9999; } } #endif // MODE_RENDER_DEPTH 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 e9722bad1f..47e6fe5873 100644 --- a/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl +++ b/servers/rendering/renderer_rd/shaders/scene_forward_lights_inc.glsl @@ -454,7 +454,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { vec3 v0 = abs(basis_normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); vec3 tangent = normalize(cross(v0, basis_normal)); vec3 bitangent = normalize(cross(tangent, basis_normal)); - float z_norm = shadow_len * omni_lights.data[idx].inv_radius; + float z_norm = 1.0 - shadow_len * omni_lights.data[idx].inv_radius; tangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; bitangent *= omni_lights.data[idx].soft_shadow_size * omni_lights.data[idx].soft_shadow_scale; @@ -479,7 +479,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { pos.xy = uv_rect.xy + pos.xy * uv_rect.zw; float d = textureLod(sampler2D(shadow_atlas, SAMPLER_LINEAR_CLAMP), pos.xy, 0.0).r; - if (d < z_norm) { + if (d > z_norm) { blocker_average += d; blocker_count += 1.0; } @@ -488,11 +488,11 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { if (blocker_count > 0.0) { //blockers found, do soft shadow blocker_average /= blocker_count; - float penumbra = (z_norm - blocker_average) / blocker_average; + float penumbra = (z_norm + blocker_average) / blocker_average; tangent *= penumbra; bitangent *= penumbra; - z_norm -= omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; + z_norm += omni_lights.data[idx].inv_radius * omni_lights.data[idx].shadow_bias; shadow = 0.0; for (uint i = 0; i < sc_penumbra_shadow_samples; i++) { @@ -536,6 +536,7 @@ float light_process_omni_shadow(uint idx, vec3 vertex, vec3 normal) { vec2 pos = shadow_sample.xy / shadow_sample.z; float depth = shadow_len - omni_lights.data[idx].shadow_bias; depth *= omni_lights.data[idx].inv_radius; + depth = 1.0 - depth; shadow = mix(1.0, sample_omni_pcf_shadow(shadow_atlas, omni_lights.data[idx].soft_shadow_scale / shadow_sample.z, pos, uv_rect, flip_offset, depth), omni_lights.data[idx].shadow_opacity); } @@ -706,7 +707,7 @@ float light_process_spot_shadow(uint idx, vec3 vertex, vec3 normal) { vec4 v = vec4(vertex + normal_bias, 1.0); vec4 splane = (spot_lights.data[idx].shadow_matrix * v); - splane.z -= spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius); + splane.z += spot_lights.data[idx].shadow_bias / (light_length * spot_lights.data[idx].inv_radius); splane /= splane.w; float shadow; diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp index 2786af65eb..d1ff9fc362 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp @@ -668,7 +668,9 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged light_data.blend_splits = (smode != RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL) && light->directional_blend_splits; for (int j = 0; j < 4; j++) { Rect2 atlas_rect = light_instance->shadow_transform[j].atlas_rect; - Projection matrix = light_instance->shadow_transform[j].camera; + Projection correction; + correction.set_depth_correction(false, true, false); + Projection matrix = correction * light_instance->shadow_transform[j].camera; float split = light_instance->shadow_transform[MIN(limit, j)].split; Projection bias; @@ -967,7 +969,9 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged Projection bias; bias.set_light_bias(); - Projection cm = light_instance->shadow_transform[0].camera; + Projection correction; + correction.set_depth_correction(false, true, false); + Projection cm = correction * light_instance->shadow_transform[0].camera; Projection shadow_mtx = bias * cm * modelview; RendererRD::MaterialStorage::store_camera(shadow_mtx, light_data.shadow_matrix); @@ -1370,6 +1374,17 @@ void LightStorage::reflection_probe_instance_set_transform(RID p_instance, const rpi->dirty = true; } +bool LightStorage::reflection_probe_has_atlas_index(RID p_instance) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); + ERR_FAIL_NULL_V(rpi, false); + + if (rpi->atlas.is_null()) { + return false; + } + + return rpi->atlas_index >= 0; +} + void LightStorage::reflection_probe_release_atlas_index(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_NULL(rpi); @@ -1384,6 +1399,14 @@ void LightStorage::reflection_probe_release_atlas_index(RID p_instance) { // TODO investigate if this is enough? shouldn't we be freeing our textures and framebuffers? + if (rpi->rendering) { + // We were cancelled mid rendering, trigger refresh. + rpi->rendering = false; + rpi->dirty = true; + rpi->processing_layer = 1; + rpi->processing_side = 0; + } + rpi->atlas_index = -1; rpi->atlas = RID(); } @@ -1535,11 +1558,10 @@ bool LightStorage::reflection_probe_instance_postprocess_step(RID p_instance) { ReflectionProbeInstance *rpi = reflection_probe_instance_owner.get_or_null(p_instance); ERR_FAIL_NULL_V(rpi, false); ERR_FAIL_COND_V(!rpi->rendering, false); - ERR_FAIL_COND_V(rpi->atlas.is_null(), false); 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) + // Does not belong to an atlas anymore, cancel (was removed from atlas or atlas changed while rendering). rpi->rendering = false; return false; } diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.h b/servers/rendering/renderer_rd/storage_rd/light_storage.h index b3d27cc6ed..b3d6bf5254 100644 --- a/servers/rendering/renderer_rd/storage_rd/light_storage.h +++ b/servers/rendering/renderer_rd/storage_rd/light_storage.h @@ -277,7 +277,6 @@ private: int processing_layer = 1; int processing_side = 0; - uint32_t render_step = 0; uint64_t last_pass = 0; uint32_t cull_mask = 0; @@ -848,6 +847,7 @@ public: virtual RID reflection_probe_instance_create(RID p_probe) override; virtual void reflection_probe_instance_free(RID p_instance) override; virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) override; + virtual bool reflection_probe_has_atlas_index(RID p_instance) override; virtual void reflection_probe_release_atlas_index(RID p_instance) override; virtual bool reflection_probe_instance_needs_redraw(RID p_instance) override; virtual bool reflection_probe_instance_has_reflection(RID p_instance) override; diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp index a854e78f53..c9c7c53d04 100644 --- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp @@ -620,8 +620,9 @@ AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) { total_amount *= particles->trail_bind_poses.size(); } + uint32_t particle_data_size = sizeof(ParticleData) + sizeof(float) * 4 * particles->userdata_count; 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()); + ERR_FAIL_COND_V(buffer.size() != (int)(total_amount * particle_data_size), AABB()); Transform3D inv = particles->emission_transform.affine_inverse(); @@ -630,7 +631,6 @@ AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) { bool first = true; const uint8_t *data_ptr = (const uint8_t *)buffer.ptr(); - uint32_t particle_data_size = sizeof(ParticleData) + sizeof(float) * particles->userdata_count; for (int i = 0; i < total_amount; i++) { const ParticleData &particle_data = *(const ParticleData *)&data_ptr[particle_data_size * i]; @@ -1388,6 +1388,11 @@ void ParticlesStorage::_particles_update_buffers(Particles *particles) { } } void ParticlesStorage::update_particles() { + if (!particle_update_list.first()) { + return; + } + + RENDER_TIMESTAMP("Update GPUParticles"); uint32_t frame = RSG::rasterizer->get_frame_number(); bool uses_motion_vectors = RSG::viewport->get_num_viewports_with_motion_vectors() > 0; while (particle_update_list.first()) { @@ -1452,6 +1457,11 @@ void ParticlesStorage::update_particles() { if (uint32_t(history_size) != particles->frame_history.size()) { particles->frame_history.resize(history_size); memset(particles->frame_history.ptr(), 0, sizeof(ParticlesFrameParams) * history_size); + // Set the frame number so that we are able to distinguish an uninitialized + // frame from the true frame number zero. See issue #88712 for details. + for (int i = 0; i < history_size; i++) { + particles->frame_history[i].frame = UINT32_MAX; + } } if (uint32_t(trail_steps) != particles->trail_params.size() || particles->frame_params_buffer.is_null()) { diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp index 8dc74820e2..c5d74d395f 100644 --- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp +++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp @@ -128,6 +128,13 @@ void RenderSceneBuffersRD::cleanup() { free_named_texture(E.value); } named_textures.clear(); + + // Clear weight_buffer / blur textures. + for (const WeightBuffers &weight_buffer : weight_buffers) { + if (weight_buffer.weight.is_valid()) { + RD::get_singleton()->free(weight_buffer.weight); + } + } } void RenderSceneBuffersRD::configure(const RenderSceneBuffersConfiguration *p_config) { diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp index dd94982f1a..da046bf6b1 100644 --- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp +++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp @@ -2965,7 +2965,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const dd.emission_rect[3] = 0; } - Color modulate = decal->modulate; + Color modulate = decal->modulate.srgb_to_linear(); dd.modulate[0] = modulate.r; dd.modulate[1] = modulate.g; dd.modulate[2] = modulate.b; @@ -3637,8 +3637,7 @@ void TextureStorage::_render_target_allocate_sdf(RenderTarget *rt) { } rt->process_size = size * scale / 100; - rt->process_size.x = MAX(rt->process_size.x, 1); - rt->process_size.y = MAX(rt->process_size.y, 1); + rt->process_size = rt->process_size.max(Size2i(1, 1)); tformat.format = RD::DATA_FORMAT_R16G16_SINT; tformat.width = rt->process_size.width; diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp index 59d70958f1..b33de9d6f4 100644 --- a/servers/rendering/renderer_scene_cull.cpp +++ b/servers/rendering/renderer_scene_cull.cpp @@ -1720,6 +1720,7 @@ void RendererSceneCull::_update_instance(Instance *p_instance) { idata.base_rid = p_instance->base; idata.parent_array_index = p_instance->visibility_parent ? p_instance->visibility_parent->array_index : -1; idata.visibility_index = p_instance->visibility_index; + idata.occlusion_timeout = 0; for (Instance *E : p_instance->visibility_dependencies) { Instance *dep_instance = E; @@ -2053,7 +2054,7 @@ void RendererSceneCull::_update_instance_lightmap_captures(Instance *p_instance) Vector3 inner_pos = ((lm_pos - bounds.position) / bounds.size) * 2.0 - Vector3(1.0, 1.0, 1.0); - real_t blend = MAX(inner_pos.x, MAX(inner_pos.y, inner_pos.z)); + real_t blend = MAX(ABS(inner_pos.x), MAX(ABS(inner_pos.y), ABS(inner_pos.z))); //make blend more rounded blend = Math::lerp(inner_pos.length(), blend, blend); blend *= blend; @@ -2775,7 +2776,7 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul #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)) +#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, cull_data.scenario->instance_data[i].occlusion_timeout)) if (!HIDDEN_BY_VISIBILITY_CHECKS) { 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)) { @@ -3482,8 +3483,13 @@ bool RendererSceneCull::_render_reflection_probe_step(Instance *p_instance, int if (p_step == 0) { if (!RSG::light_storage->reflection_probe_instance_begin_render(reflection_probe->instance, scenario->reflection_atlas)) { - return true; //all full + return true; // All full, no atlas entry to render to. } + } else if (!RSG::light_storage->reflection_probe_has_atlas_index(reflection_probe->instance)) { + // We don't have an atlas to render to, just round off. + // This is likely due to the atlas being reset. + // If so the probe will be marked as dirty and start over. + return true; } if (p_step >= 0 && p_step < 6) { @@ -3558,41 +3564,51 @@ void RendererSceneCull::render_probes() { /* REFLECTION PROBES */ SelfList<InstanceReflectionProbeData> *ref_probe = reflection_probe_render_list.first(); + Vector<SelfList<InstanceReflectionProbeData> *> done_list; bool busy = false; - while (ref_probe) { - SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); - RID base = ref_probe->self()->owner->base; + if (ref_probe) { + RENDER_TIMESTAMP("Render ReflectionProbes"); - switch (RSG::light_storage->reflection_probe_get_update_mode(base)) { - case RS::REFLECTION_PROBE_UPDATE_ONCE: { - if (busy) { //already rendering something - break; - } + while (ref_probe) { + SelfList<InstanceReflectionProbeData> *next = ref_probe->next(); + RID base = ref_probe->self()->owner->base; - bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); - if (done) { - reflection_probe_render_list.remove(ref_probe); - } else { - ref_probe->self()->render_step++; - } + switch (RSG::light_storage->reflection_probe_get_update_mode(base)) { + case RS::REFLECTION_PROBE_UPDATE_ONCE: { + if (busy) { // Already rendering something. + break; + } - busy = true; //do not render another one of this kind - } break; - case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { - int step = 0; - bool done = false; - while (!done) { - done = _render_reflection_probe_step(ref_probe->self()->owner, step); - step++; - } + bool done = _render_reflection_probe_step(ref_probe->self()->owner, ref_probe->self()->render_step); + if (done) { + done_list.push_back(ref_probe); + } else { + ref_probe->self()->render_step++; + } - reflection_probe_render_list.remove(ref_probe); - } break; + busy = true; // Do not render another one of this kind. + } break; + case RS::REFLECTION_PROBE_UPDATE_ALWAYS: { + int step = 0; + bool done = false; + while (!done) { + done = _render_reflection_probe_step(ref_probe->self()->owner, step); + step++; + } + + done_list.push_back(ref_probe); + } break; + } + + ref_probe = next; } - ref_probe = next; + // Now remove from our list + for (SelfList<InstanceReflectionProbeData> *rp : done_list) { + reflection_probe_render_list.remove(rp); + } } /* VOXEL GIS */ @@ -4241,6 +4257,7 @@ RendererSceneCull::RendererSceneCull() { indexer_update_iterations = GLOBAL_GET("rendering/limits/spatial_indexer/update_iterations_per_frame"); thread_cull_threshold = GLOBAL_GET("rendering/limits/spatial_indexer/threaded_cull_minimum_instances"); thread_cull_threshold = MAX(thread_cull_threshold, (uint32_t)WorkerThreadPool::get_singleton()->get_thread_count()); //make sure there is at least one thread per CPU + RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = GLOBAL_GET("rendering/occlusion_culling/jitter_projection"); dummy_occlusion_culling = memnew(RendererSceneOcclusionCull); diff --git a/servers/rendering/renderer_scene_cull.h b/servers/rendering/renderer_scene_cull.h index 86090aa416..0039d14475 100644 --- a/servers/rendering/renderer_scene_cull.h +++ b/servers/rendering/renderer_scene_cull.h @@ -44,7 +44,10 @@ #include "servers/rendering/rendering_method.h" #include "servers/rendering/rendering_server_globals.h" #include "servers/rendering/storage/utilities.h" + +#ifndef _3D_DISABLED #include "servers/xr/xr_interface.h" +#endif // _3D_DISABLED class RenderingLightCuller; @@ -283,6 +286,13 @@ public: Instance *instance = nullptr; int32_t parent_array_index = -1; int32_t visibility_index = -1; + + // Each time occlusion culling determines an instance is visible, + // set this to occlusion_frame plus some delay. + // Once the timeout is reached, allow the instance to be occlusion culled. + // This creates a delay for occlusion culling, which prevents flickering + // when jittering the raster occlusion projection. + uint64_t occlusion_timeout = 0; }; struct InstanceVisibilityData { diff --git a/servers/rendering/renderer_scene_occlusion_cull.cpp b/servers/rendering/renderer_scene_occlusion_cull.cpp index c4f0177c73..1f0239411a 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.cpp +++ b/servers/rendering/renderer_scene_occlusion_cull.cpp @@ -43,6 +43,8 @@ const Vector3 RendererSceneOcclusionCull::HZBuffer::corners[8] = { Vector3(1, 1, 1) }; +bool RendererSceneOcclusionCull::HZBuffer::occlusion_jitter_enabled = false; + bool RendererSceneOcclusionCull::HZBuffer::is_empty() const { return sizes.is_empty(); } @@ -66,6 +68,8 @@ void RendererSceneOcclusionCull::HZBuffer::clear() { } void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) { + occlusion_buffer_size = p_size; + if (p_size == Size2i()) { clear(); return; @@ -124,6 +128,9 @@ void RendererSceneOcclusionCull::HZBuffer::resize(const Size2i &p_size) { } void RendererSceneOcclusionCull::HZBuffer::update_mips() { + // Keep this up to date as a local to be used for occlusion timers. + occlusion_frame = Engine::get_singleton()->get_frames_drawn(); + if (sizes.is_empty()) { return; } diff --git a/servers/rendering/renderer_scene_occlusion_cull.h b/servers/rendering/renderer_scene_occlusion_cull.h index 565b393094..5adba5dc6a 100644 --- a/servers/rendering/renderer_scene_occlusion_cull.h +++ b/servers/rendering/renderer_scene_occlusion_cull.h @@ -53,19 +53,15 @@ public: PackedByteArray debug_data; float debug_tex_range = 0.0f; - public: - bool is_empty() const; - virtual void clear(); - virtual void resize(const Size2i &p_size); - - void update_mips(); + uint64_t occlusion_frame = 0; + Size2i occlusion_buffer_size; - _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const { + _FORCE_INLINE_ bool _is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near) const { if (is_empty()) { return false; } - Vector3 closest_point = Vector3(CLAMP(p_cam_position.x, p_bounds[0], p_bounds[3]), CLAMP(p_cam_position.y, p_bounds[1], p_bounds[4]), CLAMP(p_cam_position.z, p_bounds[2], p_bounds[5])); + Vector3 closest_point = p_cam_position.clamp(Vector3(p_bounds[0], p_bounds[1], p_bounds[2]), Vector3(p_bounds[3], p_bounds[4], p_bounds[5])); if (closest_point == p_cam_position) { return false; @@ -154,7 +150,47 @@ public: return !visible; } + public: + static bool occlusion_jitter_enabled; + + bool is_empty() const; + virtual void clear(); + virtual void resize(const Size2i &p_size); + + void update_mips(); + + // Thin wrapper around _is_occluded(), + // allowing occlusion timers to delay the disappearance + // of objects to prevent flickering when using jittering. + _FORCE_INLINE_ bool is_occluded(const real_t p_bounds[6], const Vector3 &p_cam_position, const Transform3D &p_cam_inv_transform, const Projection &p_cam_projection, real_t p_near, uint64_t &r_occlusion_timeout) const { + bool occluded = _is_occluded(p_bounds, p_cam_position, p_cam_inv_transform, p_cam_projection, p_near); + + // Special case, temporal jitter disabled, + // so we don't use occlusion timers. + if (!occlusion_jitter_enabled) { + return occluded; + } + + if (!occluded) { +//#define DEBUG_RASTER_OCCLUSION_JITTER +#ifdef DEBUG_RASTER_OCCLUSION_JITTER + r_occlusion_timeout = occlusion_frame + 1; +#else + r_occlusion_timeout = occlusion_frame + 9; +#endif + } else if (r_occlusion_timeout) { + // Regular timeout, allow occlusion culling + // to proceed as normal after the delay. + if (occlusion_frame >= r_occlusion_timeout) { + r_occlusion_timeout = 0; + } + } + + return occluded && !r_occlusion_timeout; + } + RID get_debug_texture(); + const Size2i &get_occlusion_buffer_size() const { return occlusion_buffer_size; } virtual ~HZBuffer(){}; }; diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp index 445a1b265e..31d5a9074c 100644 --- a/servers/rendering/renderer_viewport.cpp +++ b/servers/rendering/renderer_viewport.cpp @@ -31,6 +31,7 @@ #include "renderer_viewport.h" #include "core/config/project_settings.h" +#include "core/math/transform_interpolator.h" #include "core/object/worker_thread_pool.h" #include "renderer_canvas_cull.h" #include "renderer_scene_cull.h" @@ -220,6 +221,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) { } void RendererViewport::_draw_3d(Viewport *p_viewport) { +#ifndef _3D_DISABLED RENDER_TIMESTAMP("> Render 3D Scene"); Ref<XRInterface> xr_interface; @@ -246,6 +248,7 @@ void RendererViewport::_draw_3d(Viewport *p_viewport) { RSG::scene->render_camera(p_viewport->render_buffers, p_viewport->camera, p_viewport->scenario, p_viewport->self, p_viewport->internal_size, p_viewport->jitter_phase_count, screen_mesh_lod_threshold, p_viewport->shadow_atlas, xr_interface, &p_viewport->render_info); RENDER_TIMESTAMP("< Render 3D Scene"); +#endif // _3D_DISABLED } void RendererViewport::_draw_viewport(Viewport *p_viewport) { @@ -337,7 +340,14 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (!F->enabled) { continue; } - F->xform_cache = xf * F->xform; + + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) { + F->xform_cache = xf * F->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f); + F->xform_cache = xf * F->xform_cache; + } if (sdf_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) { F->next = occluders; @@ -376,7 +386,14 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { Vector2 offset = tsize / 2.0; cl->rect_cache = Rect2(-offset + cl->texture_offset, tsize); - cl->xform_cache = xf * cl->xform; + + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) { + cl->xform_cache = xf * cl->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f); + cl->xform_cache = xf * cl->xform_cache; + } if (clip_rect.intersects_transformed(cl->xform_cache, cl->rect_cache)) { cl->filter_next_ptr = lights; @@ -384,7 +401,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { Transform2D scale; scale.scale(cl->rect_cache.size); scale.columns[2] = cl->rect_cache.position; - cl->light_shader_xform = xf * cl->xform * scale; + cl->light_shader_xform = cl->xform_cache * scale; if (cl->use_shadow) { cl->shadows_next_ptr = lights_with_shadow; if (lights_with_shadow == nullptr) { @@ -404,7 +421,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (cl->enabled) { cl->filter_next_ptr = directional_lights; directional_lights = cl; - cl->xform_cache = xf * cl->xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !cl->interpolated) { + cl->xform_cache = xf * cl->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(cl->xform_prev, cl->xform_curr, cl->xform_cache, f); + cl->xform_cache = xf * cl->xform_cache; + } cl->xform_cache.columns[2] = Vector2(); //translation is pointless if (cl->use_shadow) { cl->shadows_next_ptr = directional_lights_with_shadow; @@ -439,7 +462,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (!F->enabled) { continue; } - F->xform_cache = xf * F->xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) { + F->xform_cache = xf * F->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f); + F->xform_cache = xf * F->xform_cache; + } if (shadow_rect.intersects_transformed(F->xform_cache, F->aabb_cache)) { F->next = occluders; occluders = F; @@ -519,7 +548,13 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { if (!F->enabled) { continue; } - F->xform_cache = xf * F->xform; + if (!RSG::canvas->_interpolation_data.interpolation_enabled || !F->interpolated) { + F->xform_cache = xf * F->xform_curr; + } else { + real_t f = Engine::get_singleton()->get_physics_interpolation_fraction(); + TransformInterpolator::interpolate_transform_2d(F->xform_prev, F->xform_curr, F->xform_cache, f); + F->xform_cache = xf * F->xform_cache; + } Transform2D localizer = F->xform_cache.affine_inverse(); for (int j = 0; j < point_count; j++) { @@ -629,6 +664,7 @@ void RendererViewport::_draw_viewport(Viewport *p_viewport) { void RendererViewport::draw_viewports(bool p_swap_buffers) { timestamp_vp_map.clear(); +#ifndef _3D_DISABLED // get our xr interface in case we need it Ref<XRInterface> xr_interface; XRServer *xr_server = XRServer::get_singleton(); @@ -639,6 +675,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { // retrieve the interface responsible for rendering xr_interface = xr_server->get_primary_interface(); } +#endif // _3D_DISABLED if (Engine::get_singleton()->is_editor_hint()) { set_default_clear_color(GLOBAL_GET("rendering/environment/defaults/default_clear_color")); @@ -671,6 +708,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { bool visible = vp->viewport_to_screen_rect != Rect2(); +#ifndef _3D_DISABLED if (vp->use_xr) { if (xr_interface.is_valid()) { // Ignore update mode we have to commit frames to our XR interface @@ -684,7 +722,9 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { visible = false; vp->size = Size2(); } - } else { + } else +#endif // _3D_DISABLED + { if (vp->update_mode == RS::VIEWPORT_UPDATE_ALWAYS || vp->update_mode == RS::VIEWPORT_UPDATE_ONCE) { visible = true; } @@ -722,6 +762,7 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { RENDER_TIMESTAMP("> Render Viewport " + itos(i)); RSG::texture_storage->render_target_set_as_unused(vp->render_target); +#ifndef _3D_DISABLED if (vp->use_xr && xr_interface.is_valid()) { // Inform XR interface we're about to render its viewport, // if this returns false we don't render. @@ -758,9 +799,9 @@ void RendererViewport::draw_viewports(bool p_swap_buffers) { RSG::rasterizer->end_viewport(p_swap_buffers && blits.size() > 0); } } - } else { - RSG::texture_storage->render_target_set_override(vp->render_target, RID(), RID(), RID()); - + } else +#endif // _3D_DISABLED + { RSG::scene->set_debug_draw_mode(vp->debug_draw); // render standard mono camera @@ -1019,6 +1060,13 @@ void RendererViewport::viewport_set_update_mode(RID p_viewport, RS::ViewportUpda viewport->update_mode = p_mode; } +RS::ViewportUpdateMode RendererViewport::viewport_get_update_mode(RID p_viewport) const { + Viewport *viewport = viewport_owner.get_or_null(p_viewport); + ERR_FAIL_NULL_V(viewport, RS::VIEWPORT_UPDATE_DISABLED); + + return viewport->update_mode; +} + RID RendererViewport::viewport_get_render_target(RID p_viewport) const { const Viewport *viewport = viewport_owner.get_or_null(p_viewport); ERR_FAIL_NULL_V(viewport, RID()); @@ -1148,6 +1196,9 @@ 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.get_or_null(p_viewport); ERR_FAIL_NULL(viewport); + if (viewport->transparent_bg == p_enabled) { + return; + } RSG::texture_storage->render_target_set_transparent(viewport->render_target, p_enabled); viewport->transparent_bg = p_enabled; diff --git a/servers/rendering/renderer_viewport.h b/servers/rendering/renderer_viewport.h index a0ec9e6318..5107398c54 100644 --- a/servers/rendering/renderer_viewport.h +++ b/servers/rendering/renderer_viewport.h @@ -37,9 +37,12 @@ #include "servers/rendering/renderer_scene_render.h" #include "servers/rendering/rendering_method.h" #include "servers/rendering_server.h" -#include "servers/xr/xr_interface.h" #include "storage/render_scene_buffers.h" +#ifndef _3D_DISABLED +#include "servers/xr/xr_interface.h" +#endif // _3D_DISABLED + class RendererViewport { public: struct CanvasBase { @@ -233,6 +236,7 @@ public: void viewport_set_texture_mipmap_bias(RID p_viewport, float p_mipmap_bias); void viewport_set_update_mode(RID p_viewport, RS::ViewportUpdateMode p_mode); + RS::ViewportUpdateMode viewport_get_update_mode(RID p_viewport) const; void viewport_set_vflip(RID p_viewport, bool p_enable); void viewport_set_clear_mode(RID p_viewport, RS::ViewportClearMode p_clear_mode); diff --git a/servers/rendering/rendering_device.cpp b/servers/rendering/rendering_device.cpp index 943d6b364b..2b6644e893 100644 --- a/servers/rendering/rendering_device.cpp +++ b/servers/rendering/rendering_device.cpp @@ -5089,14 +5089,15 @@ Error RenderingDevice::initialize(RenderingContextDriver *p_context, DisplayServ draw_list = nullptr; compute_list = nullptr; - if (main_instance) { + bool project_pipeline_cache_enable = GLOBAL_GET("rendering/rendering_device/pipeline_cache/enable"); + if (main_instance && project_pipeline_cache_enable) { // Only the instance that is not a local device and is also the singleton is allowed to manage a pipeline cache. - pipeline_cache_file_path = "user://vulkan/pipelines"; - pipeline_cache_file_path += "." + device.name.validate_filename().replace(" ", "_").to_lower(); + pipeline_cache_file_path = vformat("user://vulkan/pipelines.%s.%s", + OS::get_singleton()->get_current_rendering_method(), + device.name.validate_filename().replace(" ", "_").to_lower()); if (Engine::get_singleton()->is_editor_hint()) { pipeline_cache_file_path += ".editor"; } - pipeline_cache_file_path += ".cache"; Vector<uint8_t> cache_data = _load_pipeline_cache(); @@ -5182,7 +5183,7 @@ void RenderingDevice::_save_pipeline_cache(void *p_data) { } } -template <class T> +template <typename T> void RenderingDevice::_free_rids(T &p_owner, const char *p_type) { List<RID> owned; p_owner.get_owned_list(&owned); @@ -5223,8 +5224,12 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r case DRIVER_RESOURCE_LOGICAL_DEVICE: case DRIVER_RESOURCE_PHYSICAL_DEVICE: case DRIVER_RESOURCE_TOPMOST_OBJECT: + break; case DRIVER_RESOURCE_COMMAND_QUEUE: + driver_id = main_queue.id; + break; case DRIVER_RESOURCE_QUEUE_FAMILY: + driver_id = main_queue_family.id; break; case DRIVER_RESOURCE_TEXTURE: case DRIVER_RESOURCE_TEXTURE_VIEW: @@ -5232,19 +5237,19 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r Texture *tex = texture_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(tex, 0); - driver_id = tex->driver_id; + driver_id = tex->driver_id.id; } break; case DRIVER_RESOURCE_SAMPLER: { RDD::SamplerID *sampler_driver_id = sampler_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(sampler_driver_id, 0); - driver_id = *sampler_driver_id; + driver_id = (*sampler_driver_id).id; } break; case DRIVER_RESOURCE_UNIFORM_SET: { UniformSet *uniform_set = uniform_set_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(uniform_set, 0); - driver_id = uniform_set->driver_id; + driver_id = uniform_set->driver_id.id; } break; case DRIVER_RESOURCE_BUFFER: { Buffer *buffer = nullptr; @@ -5261,19 +5266,19 @@ uint64_t RenderingDevice::get_driver_resource(DriverResource p_resource, RID p_r } ERR_FAIL_NULL_V(buffer, 0); - driver_id = buffer->driver_id; + driver_id = buffer->driver_id.id; } break; case DRIVER_RESOURCE_COMPUTE_PIPELINE: { ComputePipeline *compute_pipeline = compute_pipeline_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(compute_pipeline, 0); - driver_id = compute_pipeline->driver_id; + driver_id = compute_pipeline->driver_id.id; } break; case DRIVER_RESOURCE_RENDER_PIPELINE: { RenderPipeline *render_pipeline = render_pipeline_owner.get_or_null(p_rid); ERR_FAIL_NULL_V(render_pipeline, 0); - driver_id = render_pipeline->driver_id; + driver_id = render_pipeline->driver_id.id; } break; default: { ERR_FAIL_V(0); diff --git a/servers/rendering/rendering_device.h b/servers/rendering/rendering_device.h index 8c88c08950..c8277024cf 100644 --- a/servers/rendering/rendering_device.h +++ b/servers/rendering/rendering_device.h @@ -1103,7 +1103,7 @@ private: public: DrawListID draw_list_begin_for_screen(DisplayServer::WindowID p_screen = 0, const Color &p_clear_color = Color()); - DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 1.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); + DrawListID draw_list_begin(RID p_framebuffer, InitialAction p_initial_color_action, FinalAction p_final_color_action, InitialAction p_initial_depth_action, FinalAction p_final_depth_action, const Vector<Color> &p_clear_color_values = Vector<Color>(), float p_clear_depth = 0.0, uint32_t p_clear_stencil = 0, const Rect2 &p_region = Rect2()); void draw_list_set_blend_constants(DrawListID p_list, const Color &p_color); void draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline); @@ -1294,7 +1294,7 @@ private: void _stall_for_previous_frames(); void _flush_and_stall_for_all_frames(); - template <class T> + template <typename T> void _free_rids(T &p_owner, const char *p_type); #ifdef DEV_ENABLED diff --git a/servers/rendering/rendering_device_commons.cpp b/servers/rendering/rendering_device_commons.cpp index c8b7980633..4dbd0e3964 100644 --- a/servers/rendering/rendering_device_commons.cpp +++ b/servers/rendering/rendering_device_commons.cpp @@ -711,12 +711,13 @@ uint32_t RenderingDeviceCommons::get_image_format_required_size(DataFormat p_for uint32_t pixel_size = get_image_format_pixel_size(p_format); uint32_t pixel_rshift = get_compressed_image_format_pixel_rshift(p_format); - uint32_t blockw, blockh; + uint32_t blockw = 0; + uint32_t blockh = 0; get_compressed_image_format_block_dimensions(p_format, blockw, blockh); for (uint32_t i = 0; i < p_mipmaps; i++) { - uint32_t bw = w % blockw != 0 ? w + (blockw - w % blockw) : w; - uint32_t bh = h % blockh != 0 ? h + (blockh - h % blockh) : h; + uint32_t bw = STEPIFY(w, blockw); + uint32_t bh = STEPIFY(h, blockh); uint32_t s = bw * bh; diff --git a/servers/rendering/rendering_device_commons.h b/servers/rendering/rendering_device_commons.h index 688a6441a7..28d641c879 100644 --- a/servers/rendering/rendering_device_commons.h +++ b/servers/rendering/rendering_device_commons.h @@ -878,6 +878,7 @@ protected: static const char *SHADER_STAGE_NAMES[SHADER_STAGE_MAX]; +public: struct ShaderUniform { UniformType type = UniformType::UNIFORM_TYPE_MAX; bool writable = false; @@ -911,6 +912,8 @@ protected: struct ShaderSpecializationConstant : public PipelineSpecializationConstant { BitField<ShaderStage> stages; + + bool operator<(const ShaderSpecializationConstant &p_other) const { return constant_id < p_other.constant_id; } }; struct ShaderDescription { @@ -925,6 +928,7 @@ protected: Vector<ShaderStage> stages; }; +protected: struct ShaderReflection : public ShaderDescription { BitField<ShaderStage> stages; BitField<ShaderStage> push_constant_stages; diff --git a/servers/rendering/rendering_device_driver.cpp b/servers/rendering/rendering_device_driver.cpp index 9e05a6a133..be74467340 100644 --- a/servers/rendering/rendering_device_driver.cpp +++ b/servers/rendering/rendering_device_driver.cpp @@ -265,6 +265,8 @@ Error RenderingDeviceDriver::_reflect_spirv(VectorView<ShaderStageSPIRVData> p_s r_reflection.specialization_constants.push_back(sconst); } } + + r_reflection.specialization_constants.sort(); } } diff --git a/servers/rendering/rendering_device_driver.h b/servers/rendering/rendering_device_driver.h index ee33dc103c..e9464ba321 100644 --- a/servers/rendering/rendering_device_driver.h +++ b/servers/rendering/rendering_device_driver.h @@ -56,7 +56,7 @@ // This may one day be used in Godot for interoperability between C arrays, Vector and LocalVector. // (See https://github.com/godotengine/godot-proposals/issues/5144.) -template <class T> +template <typename T> class VectorView { const T *_ptr = nullptr; const uint32_t _size = 0; @@ -97,20 +97,20 @@ public: #define ENUM_MEMBERS_EQUAL(m_a, m_b) ((int64_t)m_a == (int64_t)m_b) // This helps using a single paged allocator for many resource types. -template <class... RESOURCE_TYPES> +template <typename... RESOURCE_TYPES> struct VersatileResourceTemplate { static constexpr size_t RESOURCE_SIZES[] = { sizeof(RESOURCE_TYPES)... }; static constexpr size_t MAX_RESOURCE_SIZE = std::max_element(RESOURCE_SIZES, RESOURCE_SIZES + sizeof...(RESOURCE_TYPES))[0]; uint8_t data[MAX_RESOURCE_SIZE]; - template <class T> + template <typename T> static T *allocate(PagedAllocator<VersatileResourceTemplate> &p_allocator) { T *obj = (T *)p_allocator.alloc(); memnew_placement(obj, T); return obj; } - template <class T> + template <typename T> static void free(PagedAllocator<VersatileResourceTemplate> &p_allocator, T *p_object) { p_object->~T(); p_allocator.free((VersatileResourceTemplate *)p_object); @@ -128,7 +128,7 @@ public: #define DEFINE_ID(m_name) \ struct m_name##ID : public ID { \ - _ALWAYS_INLINE_ operator bool() const { return id != 0; } \ + _ALWAYS_INLINE_ explicit operator bool() const { return id != 0; } \ _ALWAYS_INLINE_ m_name##ID &operator=(m_name##ID p_other) { \ id = p_other.id; \ return *this; \ diff --git a/servers/rendering/rendering_device_graph.cpp b/servers/rendering/rendering_device_graph.cpp index 4b85d1c2bf..adac7ee3eb 100644 --- a/servers/rendering/rendering_device_graph.cpp +++ b/servers/rendering/rendering_device_graph.cpp @@ -261,7 +261,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr } if (resource_tracker->parent->usage == RESOURCE_USAGE_NONE) { - if (resource_tracker->parent->texture_driver_id != 0) { + if (resource_tracker->parent->texture_driver_id.id != 0) { // If the resource is a texture, we transition it entirely to the layout determined by the first slice that uses it. _add_texture_barrier_to_command(resource_tracker->parent->texture_driver_id, RDD::BarrierAccessBits(0), new_usage_access, RDG::RESOURCE_USAGE_NONE, new_resource_usage, resource_tracker->parent->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); } @@ -324,7 +324,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr ERR_FAIL_MSG("Texture slices that overlap can't be used in the same command."); } else { // Delete the slice from the dirty list and revert it to the usage of the parent. - if (current_tracker->texture_driver_id != 0) { + if (current_tracker->texture_driver_id.id != 0) { _add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->parent->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); // Merge the area of the slice with the current tracking area of the command and indicate it's a write usage as well. @@ -383,7 +383,7 @@ void RenderingDeviceGraph::_add_command_to_graph(ResourceTracker **p_resource_tr while (current_tracker != nullptr) { current_tracker->reset_if_outdated(tracking_frame); - if (current_tracker->texture_driver_id != 0) { + if (current_tracker->texture_driver_id.id != 0) { // Transition all slices to the layout of the parent resource. _add_texture_barrier_to_command(current_tracker->texture_driver_id, current_tracker->usage_access, new_usage_access, current_tracker->usage, resource_tracker->usage, current_tracker->texture_subresources, command_normalization_barriers, r_command->normalization_barrier_index, r_command->normalization_barrier_count); } diff --git a/servers/rendering/rendering_light_culler.cpp b/servers/rendering/rendering_light_culler.cpp index 3d82683bc2..0889898f0b 100644 --- a/servers/rendering/rendering_light_culler.cpp +++ b/servers/rendering/rendering_light_culler.cpp @@ -33,7 +33,6 @@ #include "core/math/plane.h" #include "core/math/projection.h" #include "rendering_server_globals.h" -#include "scene/3d/camera_3d.h" #ifdef RENDERING_LIGHT_CULLER_DEBUG_STRINGS const char *RenderingLightCuller::Data::string_planes[] = { @@ -428,15 +427,19 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan uint8_t *entry = &data.LUT_entries[lookup][0]; int n_edges = data.LUT_entry_sizes[lookup] - 1; + const Vector3 &pt2 = p_light_source.pos; + for (int e = 0; e < n_edges; e++) { int i0 = entry[e]; int i1 = entry[e + 1]; const Vector3 &pt0 = data.frustum_points[i0]; const Vector3 &pt1 = data.frustum_points[i1]; - // Create plane from 3 points. - Plane p(pt0, pt1, p_light_source.pos); - r_cull_planes.add_cull_plane(p); + if (!_is_colinear_tri(pt0, pt1, pt2)) { + // Create plane from 3 points. + Plane p(pt0, pt1, pt2); + r_cull_planes.add_cull_plane(p); + } } // Last to 0 edge. @@ -447,9 +450,11 @@ bool RenderingLightCuller::_add_light_camera_planes(LightCullPlanes &r_cull_plan const Vector3 &pt0 = data.frustum_points[i0]; const Vector3 &pt1 = data.frustum_points[i1]; - // Create plane from 3 points. - Plane p(pt0, pt1, p_light_source.pos); - r_cull_planes.add_cull_plane(p); + if (!_is_colinear_tri(pt0, pt1, pt2)) { + // Create plane from 3 points. + Plane p(pt0, pt1, pt2); + r_cull_planes.add_cull_plane(p); + } } #ifdef LIGHT_CULLER_DEBUG_LOGGING diff --git a/servers/rendering/rendering_light_culler.h b/servers/rendering/rendering_light_culler.h index 602543850a..0bf975430b 100644 --- a/servers/rendering/rendering_light_culler.h +++ b/servers/rendering/rendering_light_culler.h @@ -163,6 +163,39 @@ private: bool _prepare_light(const RendererSceneCull::Instance &p_instance, int32_t p_directional_light_id = -1); + // Avoid adding extra culling planes derived from near colinear triangles. + // The normals derived from these will be inaccurate, and can lead to false + // culling of objects that should be within the light volume. + bool _is_colinear_tri(const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_c) const { + // Lengths of sides a, b and c. + float la = (p_b - p_a).length(); + float lb = (p_c - p_b).length(); + float lc = (p_c - p_a).length(); + + // Get longest side into lc. + if (lb < la) { + SWAP(la, lb); + } + if (lc < lb) { + SWAP(lb, lc); + } + + // Prevent divide by zero. + if (lc > 0.00001f) { + // If the summed length of the smaller two + // sides is close to the length of the longest side, + // the points are colinear, and the triangle is near degenerate. + float ld = ((la + lb) - lc) / lc; + + // ld will be close to zero for colinear tris. + return ld < 0.00001f; + } + + // Don't create planes from tiny triangles, + // they won't be accurate. + return true; + } + // Internal version uses LightSource. bool _add_light_camera_planes(LightCullPlanes &r_cull_planes, const LightSource &p_light_source); diff --git a/servers/rendering/rendering_method.h b/servers/rendering/rendering_method.h index 4569846752..aa5e7d83cc 100644 --- a/servers/rendering/rendering_method.h +++ b/servers/rendering/rendering_method.h @@ -33,7 +33,14 @@ #include "servers/rendering/storage/render_scene_buffers.h" #include "servers/rendering_server.h" + +#ifdef _3D_DISABLED +// RendererSceneCull::render_camera is empty when 3D is disabled, but +// it and RenderingMethod::render_camera have a parameter for XRInterface. +#define XRInterface RefCounted +#else // 3D enabled #include "servers/xr/xr_interface.h" +#endif // _3D_DISABLED class RenderingMethod { public: diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp index bf8ab27722..5bf0ab0ba6 100644 --- a/servers/rendering/rendering_server_default.cpp +++ b/servers/rendering/rendering_server_default.cpp @@ -80,6 +80,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { uint64_t time_usec = OS::get_singleton()->get_ticks_usec(); + RENDER_TIMESTAMP("Prepare Render Frame"); RSG::scene->update(); //update scenes stuff before updating instances frame_setup_time = double(OS::get_singleton()->get_ticks_usec() - time_usec) / 1000.0; @@ -93,11 +94,13 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) { RSG::rasterizer->end_frame(p_swap_buffers); +#ifndef _3D_DISABLED XRServer *xr_server = XRServer::get_singleton(); if (xr_server != nullptr) { // let our XR server know we're done so we can get our frame timing xr_server->end_frame(); } +#endif // _3D_DISABLED RSG::canvas->update_visibility_notifiers(); RSG::scene->update_visibility_notifiers(); @@ -368,6 +371,16 @@ void RenderingServerDefault::_thread_loop() { _finish(); } +/* INTERPOLATION */ + +void RenderingServerDefault::tick() { + RSG::canvas->tick(); +} + +void RenderingServerDefault::set_physics_interpolation_enabled(bool p_enabled) { + RSG::canvas->set_physics_interpolation_enabled(p_enabled); +} + /* EVENT QUEUING */ void RenderingServerDefault::sync() { diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h index 17622ba311..c50472c0cd 100644 --- a/servers/rendering/rendering_server_default.h +++ b/servers/rendering/rendering_server_default.h @@ -625,6 +625,7 @@ public: FUNC2(viewport_set_texture_mipmap_bias, RID, float) FUNC2(viewport_set_update_mode, RID, ViewportUpdateMode) + FUNC1RC(ViewportUpdateMode, viewport_get_update_mode, RID) FUNC1RC(RID, viewport_get_render_target, RID) FUNC1RC(RID, viewport_get_texture, RID) @@ -852,6 +853,7 @@ public: FUNCRIDSPLIT(canvas) FUNC3(canvas_set_item_mirroring, RID, RID, const Point2 &) + FUNC3(canvas_set_item_repeat, RID, const Point2 &, int) FUNC2(canvas_set_modulate, RID, const Color &) FUNC3(canvas_set_parent, RID, RID, float) FUNC1(canvas_set_disable_scale, bool) @@ -925,6 +927,10 @@ public: FUNC1(canvas_item_set_debug_redraw, bool) FUNC0RC(bool, canvas_item_get_debug_redraw) + FUNC2(canvas_item_set_interpolated, RID, bool) + FUNC1(canvas_item_reset_physics_interpolation, RID) + FUNC2(canvas_item_transform_physics_interpolation, RID, const Transform2D &) + FUNCRIDSPLIT(canvas_light) FUNC2(canvas_light_set_mode, RID, CanvasLightMode) @@ -951,6 +957,10 @@ public: FUNC2(canvas_light_set_shadow_color, RID, const Color &) FUNC2(canvas_light_set_shadow_smooth, RID, float) + FUNC2(canvas_light_set_interpolated, RID, bool) + FUNC1(canvas_light_reset_physics_interpolation, RID) + FUNC2(canvas_light_transform_physics_interpolation, RID, const Transform2D &) + FUNCRIDSPLIT(canvas_light_occluder) FUNC2(canvas_light_occluder_attach_to_canvas, RID, RID) FUNC2(canvas_light_occluder_set_enabled, RID, bool) @@ -959,6 +969,10 @@ public: FUNC2(canvas_light_occluder_set_transform, RID, const Transform2D &) FUNC2(canvas_light_occluder_set_light_mask, RID, int) + FUNC2(canvas_light_occluder_set_interpolated, RID, bool) + FUNC1(canvas_light_occluder_reset_physics_interpolation, RID) + FUNC2(canvas_light_occluder_transform_physics_interpolation, RID, const Transform2D &) + FUNCRIDSPLIT(canvas_occluder_polygon) FUNC3(canvas_occluder_polygon_set_shape, RID, const Vector<Vector2> &, bool) @@ -1020,6 +1034,11 @@ public: } } + /* INTERPOLATION */ + + virtual void tick() override; + virtual void set_physics_interpolation_enabled(bool p_enabled) override; + /* EVENT QUEUING */ virtual void request_frame_drawn_callback(const Callable &p_callable) override; diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h index e0ec42a4d1..66106d7eb7 100644 --- a/servers/rendering/shader_compiler.h +++ b/servers/rendering/shader_compiler.h @@ -91,8 +91,8 @@ public: HashMap<StringName, String> render_mode_defines; HashMap<StringName, String> usage_defines; HashMap<StringName, String> custom_samplers; - ShaderLanguage::TextureFilter default_filter = ShaderLanguage::TextureFilter::FILTER_DEFAULT; - ShaderLanguage::TextureRepeat default_repeat = ShaderLanguage::TextureRepeat::REPEAT_DEFAULT; + ShaderLanguage::TextureFilter default_filter = ShaderLanguage::TextureFilter::FILTER_NEAREST; + ShaderLanguage::TextureRepeat default_repeat = ShaderLanguage::TextureRepeat::REPEAT_DISABLE; int base_texture_binding_index = 0; int texture_layout_set = 0; String base_uniform_string; diff --git a/servers/rendering/shader_language.h b/servers/rendering/shader_language.h index 737545b8ca..816a202b50 100644 --- a/servers/rendering/shader_language.h +++ b/servers/rendering/shader_language.h @@ -383,7 +383,7 @@ public: virtual ~Node() {} }; - template <class T> + template <typename T> T *alloc_node() { T *node = memnew(T); node->next = nodes; diff --git a/servers/rendering/storage/light_storage.h b/servers/rendering/storage/light_storage.h index 27407305d1..d439598f3d 100644 --- a/servers/rendering/storage/light_storage.h +++ b/servers/rendering/storage/light_storage.h @@ -143,6 +143,7 @@ public: virtual RID reflection_probe_instance_create(RID p_probe) = 0; virtual void reflection_probe_instance_free(RID p_instance) = 0; virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform3D &p_transform) = 0; + virtual bool reflection_probe_has_atlas_index(RID p_instance) = 0; virtual void reflection_probe_release_atlas_index(RID p_instance) = 0; virtual bool reflection_probe_instance_needs_redraw(RID p_instance) = 0; virtual bool reflection_probe_instance_has_reflection(RID p_instance) = 0; diff --git a/servers/rendering/storage/variant_converters.h b/servers/rendering/storage/variant_converters.h index 6e3c07237e..7dbdb0f517 100644 --- a/servers/rendering/storage/variant_converters.h +++ b/servers/rendering/storage/variant_converters.h @@ -242,10 +242,10 @@ inline bool is_convertible_array(Variant::Type type) { type == Variant::PACKED_COLOR_ARRAY; } -template <class, class = void> +template <typename, typename = void> inline constexpr bool is_vector_type_v = false; -template <class T> +template <typename T> inline constexpr bool is_vector_type_v<T, std::void_t<decltype(T::AXIS_COUNT)>> = true; template <typename T, typename P> diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp index e5d8800366..96d317ebd3 100644 --- a/servers/rendering_server.cpp +++ b/servers/rendering_server.cpp @@ -2209,15 +2209,15 @@ void RenderingServer::fix_surface_compatibility(SurfaceData &p_surface, const St #ifdef TOOLS_ENABLED void RenderingServer::get_argument_options(const StringName &p_function, int p_idx, List<String> *r_options) const { - String pf = p_function; + const String pf = p_function; if (p_idx == 0) { if (pf == "global_shader_parameter_set" || pf == "global_shader_parameter_set_override" || pf == "global_shader_parameter_get" || pf == "global_shader_parameter_get_type" || pf == "global_shader_parameter_remove") { - for (StringName E : global_shader_parameter_get_list()) { + for (const StringName &E : global_shader_parameter_get_list()) { r_options->push_back(E.operator String().quote()); } } else if (pf == "has_os_feature") { - for (String E : { "\"rgtc\"", "\"s3tc\"", "\"bptc\"", "\"etc\"", "\"etc2\"", "\"astc\"" }) { + for (const String E : { "\"rgtc\"", "\"s3tc\"", "\"bptc\"", "\"etc\"", "\"etc2\"", "\"astc\"" }) { r_options->push_back(E); } } @@ -2783,6 +2783,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("viewport_set_fsr_sharpness", "viewport", "sharpness"), &RenderingServer::viewport_set_fsr_sharpness); ClassDB::bind_method(D_METHOD("viewport_set_texture_mipmap_bias", "viewport", "mipmap_bias"), &RenderingServer::viewport_set_texture_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_get_update_mode", "viewport"), &RenderingServer::viewport_get_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_render_target", "viewport"), &RenderingServer::viewport_get_render_target); ClassDB::bind_method(D_METHOD("viewport_get_texture", "viewport"), &RenderingServer::viewport_get_texture); @@ -3186,6 +3187,7 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_create"), &RenderingServer::canvas_create); ClassDB::bind_method(D_METHOD("canvas_set_item_mirroring", "canvas", "item", "mirroring"), &RenderingServer::canvas_set_item_mirroring); + ClassDB::bind_method(D_METHOD("canvas_set_item_repeat", "item", "repeat_size", "repeat_times"), &RenderingServer::canvas_set_item_repeat); ClassDB::bind_method(D_METHOD("canvas_set_modulate", "canvas", "color"), &RenderingServer::canvas_set_modulate); ClassDB::bind_method(D_METHOD("canvas_set_disable_scale", "disable"), &RenderingServer::canvas_set_disable_scale); @@ -3218,6 +3220,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_item_set_modulate", "item", "color"), &RenderingServer::canvas_item_set_modulate); ClassDB::bind_method(D_METHOD("canvas_item_set_self_modulate", "item", "color"), &RenderingServer::canvas_item_set_self_modulate); ClassDB::bind_method(D_METHOD("canvas_item_set_draw_behind_parent", "item", "enabled"), &RenderingServer::canvas_item_set_draw_behind_parent); + ClassDB::bind_method(D_METHOD("canvas_item_set_interpolated", "item", "interpolated"), &RenderingServer::canvas_item_set_interpolated); + ClassDB::bind_method(D_METHOD("canvas_item_reset_physics_interpolation", "item"), &RenderingServer::canvas_item_reset_physics_interpolation); + ClassDB::bind_method(D_METHOD("canvas_item_transform_physics_interpolation", "item", "transform"), &RenderingServer::canvas_item_transform_physics_interpolation); /* Primitives */ @@ -3301,6 +3306,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_color", "light", "color"), &RenderingServer::canvas_light_set_shadow_color); ClassDB::bind_method(D_METHOD("canvas_light_set_shadow_smooth", "light", "smooth"), &RenderingServer::canvas_light_set_shadow_smooth); ClassDB::bind_method(D_METHOD("canvas_light_set_blend_mode", "light", "mode"), &RenderingServer::canvas_light_set_blend_mode); + ClassDB::bind_method(D_METHOD("canvas_light_set_interpolated", "light", "interpolated"), &RenderingServer::canvas_light_set_interpolated); + ClassDB::bind_method(D_METHOD("canvas_light_reset_physics_interpolation", "light"), &RenderingServer::canvas_light_reset_physics_interpolation); + ClassDB::bind_method(D_METHOD("canvas_light_transform_physics_interpolation", "light", "transform"), &RenderingServer::canvas_light_transform_physics_interpolation); BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_POINT); BIND_ENUM_CONSTANT(CANVAS_LIGHT_MODE_DIRECTIONAL); @@ -3323,6 +3331,9 @@ void RenderingServer::_bind_methods() { ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_as_sdf_collision", "occluder", "enable"), &RenderingServer::canvas_light_occluder_set_as_sdf_collision); ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_transform", "occluder", "transform"), &RenderingServer::canvas_light_occluder_set_transform); ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_light_mask", "occluder", "mask"), &RenderingServer::canvas_light_occluder_set_light_mask); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_set_interpolated", "occluder", "interpolated"), &RenderingServer::canvas_light_occluder_set_interpolated); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_reset_physics_interpolation", "occluder"), &RenderingServer::canvas_light_occluder_reset_physics_interpolation); + ClassDB::bind_method(D_METHOD("canvas_light_occluder_transform_physics_interpolation", "occluder", "transform"), &RenderingServer::canvas_light_occluder_transform_physics_interpolation); /* CANVAS LIGHT OCCLUDER POLYGON */ diff --git a/servers/rendering_server.h b/servers/rendering_server.h index 02a90dad3b..8f0150f180 100644 --- a/servers/rendering_server.h +++ b/servers/rendering_server.h @@ -873,6 +873,7 @@ public: }; virtual void viewport_set_update_mode(RID p_viewport, ViewportUpdateMode p_mode) = 0; + virtual ViewportUpdateMode viewport_get_update_mode(RID p_viewport) const = 0; enum ViewportClearMode { VIEWPORT_CLEAR_ALWAYS, @@ -1378,6 +1379,7 @@ public: virtual RID canvas_create() = 0; virtual void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring) = 0; + virtual void canvas_set_item_repeat(RID p_item, const Point2 &p_repeat_size, int p_repeat_times) = 0; virtual void canvas_set_modulate(RID p_canvas, const Color &p_color) = 0; virtual void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) = 0; @@ -1475,6 +1477,10 @@ public: virtual void canvas_item_set_debug_redraw(bool p_enabled) = 0; virtual bool canvas_item_get_debug_redraw() const = 0; + virtual void canvas_item_set_interpolated(RID p_item, bool p_interpolated) = 0; + virtual void canvas_item_reset_physics_interpolation(RID p_item) = 0; + virtual void canvas_item_transform_physics_interpolation(RID p_item, const Transform2D &p_transform) = 0; + /* CANVAS LIGHT */ virtual RID canvas_light_create() = 0; @@ -1522,6 +1528,10 @@ public: virtual void canvas_light_set_shadow_color(RID p_light, const Color &p_color) = 0; virtual void canvas_light_set_shadow_smooth(RID p_light, float p_smooth) = 0; + virtual void canvas_light_set_interpolated(RID p_light, bool p_interpolated) = 0; + virtual void canvas_light_reset_physics_interpolation(RID p_light) = 0; + virtual void canvas_light_transform_physics_interpolation(RID p_light, const Transform2D &p_transform) = 0; + /* CANVAS LIGHT OCCLUDER */ virtual RID canvas_light_occluder_create() = 0; @@ -1532,6 +1542,10 @@ public: virtual void canvas_light_occluder_set_transform(RID p_occluder, const Transform2D &p_xform) = 0; virtual void canvas_light_occluder_set_light_mask(RID p_occluder, int p_mask) = 0; + virtual void canvas_light_occluder_set_interpolated(RID p_occluder, bool p_interpolated) = 0; + virtual void canvas_light_occluder_reset_physics_interpolation(RID p_occluder) = 0; + virtual void canvas_light_occluder_transform_physics_interpolation(RID p_occluder, const Transform2D &p_transform) = 0; + /* CANVAS LIGHT OCCLUDER POLYGON */ virtual RID canvas_occluder_polygon_create() = 0; @@ -1603,6 +1617,11 @@ public: virtual void free(RID p_rid) = 0; // Free RIDs associated with the rendering server. + /* INTERPOLATION */ + + virtual void tick() = 0; + virtual void set_physics_interpolation_enabled(bool p_enabled) = 0; + /* EVENT QUEUING */ virtual void request_frame_drawn_callback(const Callable &p_callable) = 0; diff --git a/servers/text/text_server_dummy.h b/servers/text/text_server_dummy.h index 77b6ecf319..a5ab444f55 100644 --- a/servers/text/text_server_dummy.h +++ b/servers/text/text_server_dummy.h @@ -40,9 +40,87 @@ class TextServerDummy : public TextServerExtension { _THREAD_SAFE_CLASS_ public: - virtual String get_name() const override { - return "Dummy"; - } + virtual bool has_feature(Feature p_feature) const override { return false; } + virtual String get_name() const override { return "Dummy"; } + virtual int64_t get_features() const override { return 0; } + virtual void free_rid(const RID &p_rid) override {} + virtual bool has(const RID &p_rid) override { return false; } + + virtual RID create_font() override { return RID(); } + virtual void font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) override {} + virtual int64_t font_get_fixed_size(const RID &p_font_rid) const override { return 0; } + virtual void font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) override {} + virtual TextServer::FixedSizeScaleMode font_get_fixed_size_scale_mode(const RID &p_font_rid) const override { return FIXED_SIZE_SCALE_DISABLE; } + virtual TypedArray<Vector2i> font_get_size_cache_list(const RID &p_font_rid) const override { return TypedArray<Vector2i>(); } + virtual void font_clear_size_cache(const RID &p_font_rid) override {} + virtual void font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) override {} + virtual void font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) override {} + virtual double font_get_ascent(const RID &p_font_rid, int64_t p_size) const override { return 0; } + virtual void font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) override {} + virtual double font_get_descent(const RID &p_font_rid, int64_t p_size) const override { return 0; } + virtual void font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) override {} + virtual double font_get_underline_position(const RID &p_font_rid, int64_t p_size) const override { return 0; } + virtual void font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) override {} + virtual double font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const override { return 0; } + virtual void font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) override {} + virtual double font_get_scale(const RID &p_font_rid, int64_t p_size) const override { return 0; } + virtual int64_t font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const override { return 0; } + virtual void font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) override {} + virtual void font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) override {} + virtual void font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) override {} + virtual Ref<Image> font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const override { return Ref<Image>(); } + virtual PackedInt32Array font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const override { return PackedInt32Array(); } + virtual void font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) override {} + virtual void font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) override {} + virtual Vector2 font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const override { return Vector2(); } + virtual void font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) override {} + virtual Vector2 font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return Vector2(); } + virtual void font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) override {} + virtual Vector2 font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return Vector2(); } + virtual void font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) override {} + virtual Rect2 font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return Rect2(); } + virtual void font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Rect2 &p_uv_rect) override {} + virtual int64_t font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return 0; } + virtual void font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) override {} + virtual RID font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return RID(); } + virtual Size2 font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const override { return Size2(); } + virtual int64_t font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const override { return 0; } + virtual int64_t font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const override { return 0; } + virtual bool font_has_char(const RID &p_font_rid, int64_t p_char) const override { return false; } + virtual String font_get_supported_chars(const RID &p_font_rid) const override { return String(); } + virtual void font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {} + virtual void font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_t p_index, const Color &p_color) const override {} + + virtual RID create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) override { return RID(); } + virtual void shaped_text_clear(const RID &p_shaped) override {} + virtual bool shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) override { return false; } + virtual bool shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, double p_baseline) override { return false; } + virtual bool shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) override { return false; } + virtual int64_t shaped_get_span_count(const RID &p_shaped) const override { return 0; } + virtual Variant shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const override { return Variant(); } + virtual void shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) override {} + virtual RID shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const override { return RID(); } + virtual RID shaped_text_get_parent(const RID &p_shaped) const override { return RID(); } + virtual bool shaped_text_shape(const RID &p_shaped) override { return false; } + virtual bool shaped_text_is_ready(const RID &p_shaped) const override { return false; } + virtual const Glyph *shaped_text_get_glyphs(const RID &p_shaped) const override { return nullptr; } + virtual const Glyph *shaped_text_sort_logical(const RID &p_shaped) override { return nullptr; } + virtual int64_t shaped_text_get_glyph_count(const RID &p_shaped) const override { return 0; } + virtual Vector2i shaped_text_get_range(const RID &p_shaped) const override { return Vector2i(); } + virtual int64_t shaped_text_get_trim_pos(const RID &p_shaped) const override { return -1; } + virtual int64_t shaped_text_get_ellipsis_pos(const RID &p_shaped) const override { return -1; } + virtual const Glyph *shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const override { return nullptr; } + virtual int64_t shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const override { return -1; } + virtual Array shaped_text_get_objects(const RID &p_shaped) const override { return Array(); } + virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override { return Rect2(); } + virtual Vector2i shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const override { return Vector2i(); } + virtual int64_t shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const override { return -1; } + virtual Size2 shaped_text_get_size(const RID &p_shaped) const override { return Size2(); } + virtual double shaped_text_get_ascent(const RID &p_shaped) const override { return 0; } + virtual double shaped_text_get_descent(const RID &p_shaped) const override { return 0; } + virtual double shaped_text_get_width(const RID &p_shaped) const override { return 0; } + virtual double shaped_text_get_underline_position(const RID &p_shaped) const override { return 0; } + virtual double shaped_text_get_underline_thickness(const RID &p_shaped) const override { return 0; } }; #endif // TEXT_SERVER_DUMMY_H diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp index d5080e586d..53e1d119fd 100644 --- a/servers/text/text_server_extension.cpp +++ b/servers/text/text_server_extension.cpp @@ -80,6 +80,9 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_font_set_antialiasing, "font_rid", "antialiasing"); GDVIRTUAL_BIND(_font_get_antialiasing, "font_rid"); + GDVIRTUAL_BIND(_font_set_disable_embedded_bitmaps, "font_rid", "disable_embedded_bitmaps"); + GDVIRTUAL_BIND(_font_get_disable_embedded_bitmaps, "font_rid"); + GDVIRTUAL_BIND(_font_set_generate_mipmaps, "font_rid", "generate_mipmaps"); GDVIRTUAL_BIND(_font_get_generate_mipmaps, "font_rid"); @@ -293,6 +296,8 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_get_objects, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_object_rect, "shaped", "key"); + GDVIRTUAL_BIND(_shaped_text_get_object_range, "shaped", "key"); + GDVIRTUAL_BIND(_shaped_text_get_object_glyph, "shaped", "key"); GDVIRTUAL_BIND(_shaped_text_get_size, "shaped"); GDVIRTUAL_BIND(_shaped_text_get_ascent, "shaped"); @@ -321,8 +326,8 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_shaped_text_prev_character_pos, "shaped", "pos"); GDVIRTUAL_BIND(_shaped_text_closest_character_pos, "shaped", "pos"); - GDVIRTUAL_BIND(_format_number, "string", "language"); - GDVIRTUAL_BIND(_parse_number, "string", "language"); + GDVIRTUAL_BIND(_format_number, "number", "language"); + GDVIRTUAL_BIND(_parse_number, "number", "language"); GDVIRTUAL_BIND(_percent_sign, "language"); GDVIRTUAL_BIND(_strip_diacritics, "string"); @@ -336,6 +341,7 @@ void TextServerExtension::_bind_methods() { GDVIRTUAL_BIND(_string_to_upper, "string", "language"); GDVIRTUAL_BIND(_string_to_lower, "string", "language"); + GDVIRTUAL_BIND(_string_to_title, "string", "language"); GDVIRTUAL_BIND(_parse_structured_text, "parser_type", "args", "text"); @@ -344,29 +350,29 @@ void TextServerExtension::_bind_methods() { bool TextServerExtension::has_feature(Feature p_feature) const { bool ret = false; - GDVIRTUAL_CALL(_has_feature, p_feature, ret); + GDVIRTUAL_REQUIRED_CALL(_has_feature, p_feature, ret); return ret; } String TextServerExtension::get_name() const { String ret = "Unknown"; - GDVIRTUAL_CALL(_get_name, ret); + GDVIRTUAL_REQUIRED_CALL(_get_name, ret); return ret; } int64_t TextServerExtension::get_features() const { int64_t ret = 0; - GDVIRTUAL_CALL(_get_features, ret); + GDVIRTUAL_REQUIRED_CALL(_get_features, ret); return ret; } void TextServerExtension::free_rid(const RID &p_rid) { - GDVIRTUAL_CALL(_free_rid, p_rid); + GDVIRTUAL_REQUIRED_CALL(_free_rid, p_rid); } bool TextServerExtension::has(const RID &p_rid) { bool ret = false; - GDVIRTUAL_CALL(_has, p_rid, ret); + GDVIRTUAL_REQUIRED_CALL(_has, p_rid, ret); return ret; } @@ -402,14 +408,18 @@ bool TextServerExtension::is_locale_right_to_left(const String &p_locale) const int64_t TextServerExtension::name_to_tag(const String &p_name) const { int64_t ret = 0; - GDVIRTUAL_CALL(_name_to_tag, p_name, ret); - return ret; + if (GDVIRTUAL_CALL(_name_to_tag, p_name, ret)) { + return ret; + } + return TextServer::name_to_tag(p_name); } String TextServerExtension::tag_to_name(int64_t p_tag) const { String ret; - GDVIRTUAL_CALL(_tag_to_name, p_tag, ret); - return ret; + if (GDVIRTUAL_CALL(_tag_to_name, p_tag, ret)) { + return ret; + } + return TextServer::tag_to_name(p_tag); } /*************************************************************************/ @@ -418,7 +428,7 @@ String TextServerExtension::tag_to_name(int64_t p_tag) const { RID TextServerExtension::create_font() { RID ret; - GDVIRTUAL_CALL(_create_font, ret); + GDVIRTUAL_REQUIRED_CALL(_create_font, ret); return ret; } @@ -447,7 +457,7 @@ int64_t TextServerExtension::font_get_face_index(const RID &p_font_rid) const { } int64_t TextServerExtension::font_get_face_count(const RID &p_font_rid) const { - int64_t ret = 0; + int64_t ret = 1; GDVIRTUAL_CALL(_font_get_face_count, p_font_rid, ret); return ret; } @@ -518,6 +528,16 @@ TextServer::FontAntialiasing TextServerExtension::font_get_antialiasing(const RI return ret; } +void TextServerExtension::font_set_disable_embedded_bitmaps(const RID &p_font_rid, bool p_disable_embedded_bitmaps) { + GDVIRTUAL_CALL(_font_set_disable_embedded_bitmaps, p_font_rid, p_disable_embedded_bitmaps); +} + +bool TextServerExtension::font_get_disable_embedded_bitmaps(const RID &p_font_rid) const { + bool ret = false; + GDVIRTUAL_CALL(_font_get_disable_embedded_bitmaps, p_font_rid, ret); + return ret; +} + void TextServerExtension::font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) { GDVIRTUAL_CALL(_font_set_generate_mipmaps, p_font_rid, p_generate_mipmaps); } @@ -559,22 +579,22 @@ int64_t TextServerExtension::font_get_msdf_size(const RID &p_font_rid) const { } void TextServerExtension::font_set_fixed_size(const RID &p_font_rid, int64_t p_fixed_size) { - GDVIRTUAL_CALL(_font_set_fixed_size, p_font_rid, p_fixed_size); + GDVIRTUAL_REQUIRED_CALL(_font_set_fixed_size, p_font_rid, p_fixed_size); } int64_t TextServerExtension::font_get_fixed_size(const RID &p_font_rid) const { int64_t ret = 0; - GDVIRTUAL_CALL(_font_get_fixed_size, p_font_rid, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_fixed_size, p_font_rid, ret); return ret; } void TextServerExtension::font_set_fixed_size_scale_mode(const RID &p_font_rid, TextServer::FixedSizeScaleMode p_fixed_size_scale_mode) { - GDVIRTUAL_CALL(_font_set_fixed_size_scale_mode, p_font_rid, p_fixed_size_scale_mode); + GDVIRTUAL_REQUIRED_CALL(_font_set_fixed_size_scale_mode, p_font_rid, p_fixed_size_scale_mode); } TextServer::FixedSizeScaleMode TextServerExtension::font_get_fixed_size_scale_mode(const RID &p_font_rid) const { FixedSizeScaleMode ret = FIXED_SIZE_SCALE_DISABLE; - GDVIRTUAL_CALL(_font_get_fixed_size_scale_mode, p_font_rid, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_fixed_size_scale_mode, p_font_rid, ret); return ret; } @@ -680,89 +700,89 @@ double TextServerExtension::font_get_oversampling(const RID &p_font_rid) const { TypedArray<Vector2i> TextServerExtension::font_get_size_cache_list(const RID &p_font_rid) const { TypedArray<Vector2i> ret; - GDVIRTUAL_CALL(_font_get_size_cache_list, p_font_rid, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_size_cache_list, p_font_rid, ret); return ret; } void TextServerExtension::font_clear_size_cache(const RID &p_font_rid) { - GDVIRTUAL_CALL(_font_clear_size_cache, p_font_rid); + GDVIRTUAL_REQUIRED_CALL(_font_clear_size_cache, p_font_rid); } void TextServerExtension::font_remove_size_cache(const RID &p_font_rid, const Vector2i &p_size) { - GDVIRTUAL_CALL(_font_remove_size_cache, p_font_rid, p_size); + GDVIRTUAL_REQUIRED_CALL(_font_remove_size_cache, p_font_rid, p_size); } void TextServerExtension::font_set_ascent(const RID &p_font_rid, int64_t p_size, double p_ascent) { - GDVIRTUAL_CALL(_font_set_ascent, p_font_rid, p_size, p_ascent); + GDVIRTUAL_REQUIRED_CALL(_font_set_ascent, p_font_rid, p_size, p_ascent); } double TextServerExtension::font_get_ascent(const RID &p_font_rid, int64_t p_size) const { double ret = 0; - GDVIRTUAL_CALL(_font_get_ascent, p_font_rid, p_size, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_ascent, p_font_rid, p_size, ret); return ret; } void TextServerExtension::font_set_descent(const RID &p_font_rid, int64_t p_size, double p_descent) { - GDVIRTUAL_CALL(_font_set_descent, p_font_rid, p_size, p_descent); + GDVIRTUAL_REQUIRED_CALL(_font_set_descent, p_font_rid, p_size, p_descent); } double TextServerExtension::font_get_descent(const RID &p_font_rid, int64_t p_size) const { double ret = 0; - GDVIRTUAL_CALL(_font_get_descent, p_font_rid, p_size, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_descent, p_font_rid, p_size, ret); return ret; } void TextServerExtension::font_set_underline_position(const RID &p_font_rid, int64_t p_size, double p_underline_position) { - GDVIRTUAL_CALL(_font_set_underline_position, p_font_rid, p_size, p_underline_position); + GDVIRTUAL_REQUIRED_CALL(_font_set_underline_position, p_font_rid, p_size, p_underline_position); } double TextServerExtension::font_get_underline_position(const RID &p_font_rid, int64_t p_size) const { double ret = 0; - GDVIRTUAL_CALL(_font_get_underline_position, p_font_rid, p_size, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_underline_position, p_font_rid, p_size, ret); return ret; } void TextServerExtension::font_set_underline_thickness(const RID &p_font_rid, int64_t p_size, double p_underline_thickness) { - GDVIRTUAL_CALL(_font_set_underline_thickness, p_font_rid, p_size, p_underline_thickness); + GDVIRTUAL_REQUIRED_CALL(_font_set_underline_thickness, p_font_rid, p_size, p_underline_thickness); } double TextServerExtension::font_get_underline_thickness(const RID &p_font_rid, int64_t p_size) const { double ret = 0; - GDVIRTUAL_CALL(_font_get_underline_thickness, p_font_rid, p_size, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_underline_thickness, p_font_rid, p_size, ret); return ret; } void TextServerExtension::font_set_scale(const RID &p_font_rid, int64_t p_size, double p_scale) { - GDVIRTUAL_CALL(_font_set_scale, p_font_rid, p_size, p_scale); + GDVIRTUAL_REQUIRED_CALL(_font_set_scale, p_font_rid, p_size, p_scale); } double TextServerExtension::font_get_scale(const RID &p_font_rid, int64_t p_size) const { double ret = 0; - GDVIRTUAL_CALL(_font_get_scale, p_font_rid, p_size, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_scale, p_font_rid, p_size, ret); return ret; } int64_t TextServerExtension::font_get_texture_count(const RID &p_font_rid, const Vector2i &p_size) const { int64_t ret = 0; - GDVIRTUAL_CALL(_font_get_texture_count, p_font_rid, p_size, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_texture_count, p_font_rid, p_size, ret); return ret; } void TextServerExtension::font_clear_textures(const RID &p_font_rid, const Vector2i &p_size) { - GDVIRTUAL_CALL(_font_clear_textures, p_font_rid, p_size); + GDVIRTUAL_REQUIRED_CALL(_font_clear_textures, p_font_rid, p_size); } void TextServerExtension::font_remove_texture(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) { - GDVIRTUAL_CALL(_font_remove_texture, p_font_rid, p_size, p_texture_index); + GDVIRTUAL_REQUIRED_CALL(_font_remove_texture, p_font_rid, p_size, p_texture_index); } void TextServerExtension::font_set_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index, const Ref<Image> &p_image) { - GDVIRTUAL_CALL(_font_set_texture_image, p_font_rid, p_size, p_texture_index, p_image); + GDVIRTUAL_REQUIRED_CALL(_font_set_texture_image, p_font_rid, p_size, p_texture_index, p_image); } Ref<Image> TextServerExtension::font_get_texture_image(const RID &p_font_rid, const Vector2i &p_size, int64_t p_texture_index) const { Ref<Image> ret; - GDVIRTUAL_CALL(_font_get_texture_image, p_font_rid, p_size, p_texture_index, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_texture_image, p_font_rid, p_size, p_texture_index, ret); return ret; } @@ -778,77 +798,77 @@ PackedInt32Array TextServerExtension::font_get_texture_offsets(const RID &p_font PackedInt32Array TextServerExtension::font_get_glyph_list(const RID &p_font_rid, const Vector2i &p_size) const { PackedInt32Array ret; - GDVIRTUAL_CALL(_font_get_glyph_list, p_font_rid, p_size, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_list, p_font_rid, p_size, ret); return ret; } void TextServerExtension::font_clear_glyphs(const RID &p_font_rid, const Vector2i &p_size) { - GDVIRTUAL_CALL(_font_clear_glyphs, p_font_rid, p_size); + GDVIRTUAL_REQUIRED_CALL(_font_clear_glyphs, p_font_rid, p_size); } void TextServerExtension::font_remove_glyph(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) { - GDVIRTUAL_CALL(_font_remove_glyph, p_font_rid, p_size, p_glyph); + GDVIRTUAL_REQUIRED_CALL(_font_remove_glyph, p_font_rid, p_size, p_glyph); } Vector2 TextServerExtension::font_get_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph) const { Vector2 ret; - GDVIRTUAL_CALL(_font_get_glyph_advance, p_font_rid, p_size, p_glyph, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_advance, p_font_rid, p_size, p_glyph, ret); return ret; } void TextServerExtension::font_set_glyph_advance(const RID &p_font_rid, int64_t p_size, int64_t p_glyph, const Vector2 &p_advance) { - GDVIRTUAL_CALL(_font_set_glyph_advance, p_font_rid, p_size, p_glyph, p_advance); + GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_advance, p_font_rid, p_size, p_glyph, p_advance); } Vector2 TextServerExtension::font_get_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { Vector2 ret; - GDVIRTUAL_CALL(_font_get_glyph_offset, p_font_rid, p_size, p_glyph, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_offset, p_font_rid, p_size, p_glyph, ret); return ret; } void TextServerExtension::font_set_glyph_offset(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_offset) { - GDVIRTUAL_CALL(_font_set_glyph_offset, p_font_rid, p_size, p_glyph, p_offset); + GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_offset, p_font_rid, p_size, p_glyph, p_offset); } Vector2 TextServerExtension::font_get_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { Vector2 ret; - GDVIRTUAL_CALL(_font_get_glyph_size, p_font_rid, p_size, p_glyph, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_size, p_font_rid, p_size, p_glyph, ret); return ret; } void TextServerExtension::font_set_glyph_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, const Vector2 &p_gl_size) { - GDVIRTUAL_CALL(_font_set_glyph_size, p_font_rid, p_size, p_glyph, p_gl_size); + GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_size, p_font_rid, p_size, p_glyph, p_gl_size); } Rect2 TextServerExtension::font_get_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { Rect2 ret; - GDVIRTUAL_CALL(_font_get_glyph_uv_rect, p_font_rid, p_size, p_glyph, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_uv_rect, p_font_rid, p_size, p_glyph, ret); return ret; } void TextServerExtension::font_set_glyph_uv_rect(const RID &p_font_rid, const Vector2i &p_size, int64_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); + GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_uv_rect, p_font_rid, p_size, p_glyph, p_uv_rect); } int64_t TextServerExtension::font_get_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { int64_t ret = 0; - GDVIRTUAL_CALL(_font_get_glyph_texture_idx, p_font_rid, p_size, p_glyph, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_texture_idx, p_font_rid, p_size, p_glyph, ret); return ret; } void TextServerExtension::font_set_glyph_texture_idx(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph, int64_t p_texture_idx) { - GDVIRTUAL_CALL(_font_set_glyph_texture_idx, p_font_rid, p_size, p_glyph, p_texture_idx); + GDVIRTUAL_REQUIRED_CALL(_font_set_glyph_texture_idx, p_font_rid, p_size, p_glyph, p_texture_idx); } RID TextServerExtension::font_get_glyph_texture_rid(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { RID ret; - GDVIRTUAL_CALL(_font_get_glyph_texture_rid, p_font_rid, p_size, p_glyph, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_texture_rid, p_font_rid, p_size, p_glyph, ret); return ret; } Size2 TextServerExtension::font_get_glyph_texture_size(const RID &p_font_rid, const Vector2i &p_size, int64_t p_glyph) const { Size2 ret; - GDVIRTUAL_CALL(_font_get_glyph_texture_size, p_font_rid, p_size, p_glyph, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_texture_size, p_font_rid, p_size, p_glyph, ret); return ret; } @@ -884,25 +904,25 @@ Vector2 TextServerExtension::font_get_kerning(const RID &p_font_rid, int64_t p_s int64_t TextServerExtension::font_get_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_char, int64_t p_variation_selector) const { int64_t ret = 0; - GDVIRTUAL_CALL(_font_get_glyph_index, p_font_rid, p_size, p_char, p_variation_selector, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_glyph_index, p_font_rid, p_size, p_char, p_variation_selector, ret); return ret; } int64_t TextServerExtension::font_get_char_from_glyph_index(const RID &p_font_rid, int64_t p_size, int64_t p_glyph_index) const { int64_t ret = 0; - GDVIRTUAL_CALL(_font_get_char_from_glyph_index, p_font_rid, p_size, p_glyph_index, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_char_from_glyph_index, p_font_rid, p_size, p_glyph_index, ret); return ret; } bool TextServerExtension::font_has_char(const RID &p_font_rid, int64_t p_char) const { bool ret = false; - GDVIRTUAL_CALL(_font_has_char, p_font_rid, p_char, ret); + GDVIRTUAL_REQUIRED_CALL(_font_has_char, p_font_rid, p_char, ret); return ret; } String TextServerExtension::font_get_supported_chars(const RID &p_font_rid) const { String ret; - GDVIRTUAL_CALL(_font_get_supported_chars, p_font_rid, ret); + GDVIRTUAL_REQUIRED_CALL(_font_get_supported_chars, p_font_rid, ret); return ret; } @@ -915,11 +935,11 @@ void TextServerExtension::font_render_glyph(const RID &p_font_rid, const Vector2 } void TextServerExtension::font_draw_glyph(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, const Vector2 &p_pos, int64_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); + GDVIRTUAL_REQUIRED_CALL(_font_draw_glyph, p_font_rid, p_canvas, p_size, p_pos, p_index, p_color); } void TextServerExtension::font_draw_glyph_outline(const RID &p_font_rid, const RID &p_canvas, int64_t p_size, int64_t p_outline_size, const Vector2 &p_pos, int64_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); + GDVIRTUAL_REQUIRED_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(const RID &p_font_rid, const String &p_language) const { @@ -1026,12 +1046,12 @@ void TextServerExtension::draw_hex_code_box(const RID &p_canvas, int64_t p_size, RID TextServerExtension::create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) { RID ret; - GDVIRTUAL_CALL(_create_shaped_text, p_direction, p_orientation, ret); + GDVIRTUAL_REQUIRED_CALL(_create_shaped_text, p_direction, p_orientation, ret); return ret; } void TextServerExtension::shaped_text_clear(const RID &p_shaped) { - GDVIRTUAL_CALL(_shaped_text_clear, p_shaped); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_clear, p_shaped); } void TextServerExtension::shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) { @@ -1116,47 +1136,47 @@ int64_t TextServerExtension::shaped_text_get_spacing(const RID &p_shaped, TextSe bool TextServerExtension::shaped_text_add_string(const RID &p_shaped, const String &p_text, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features, const String &p_language, const Variant &p_meta) { bool ret = false; - GDVIRTUAL_CALL(_shaped_text_add_string, p_shaped, p_text, p_fonts, p_size, p_opentype_features, p_language, p_meta, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_add_string, p_shaped, p_text, p_fonts, p_size, p_opentype_features, p_language, p_meta, ret); return ret; } bool TextServerExtension::shaped_text_add_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, int64_t p_length, double p_baseline) { bool ret = false; - GDVIRTUAL_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, p_baseline, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_add_object, p_shaped, p_key, p_size, p_inline_align, p_length, p_baseline, ret); return ret; } bool TextServerExtension::shaped_text_resize_object(const RID &p_shaped, const Variant &p_key, const Size2 &p_size, InlineAlignment p_inline_align, double p_baseline) { bool ret = false; - GDVIRTUAL_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, p_baseline, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_resize_object, p_shaped, p_key, p_size, p_inline_align, p_baseline, ret); return ret; } int64_t TextServerExtension::shaped_get_span_count(const RID &p_shaped) const { int64_t ret = 0; - GDVIRTUAL_CALL(_shaped_get_span_count, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_get_span_count, p_shaped, ret); return ret; } Variant TextServerExtension::shaped_get_span_meta(const RID &p_shaped, int64_t p_index) const { Variant ret = false; - GDVIRTUAL_CALL(_shaped_get_span_meta, p_shaped, p_index, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_get_span_meta, p_shaped, p_index, ret); return ret; } void TextServerExtension::shaped_set_span_update_font(const RID &p_shaped, int64_t p_index, const TypedArray<RID> &p_fonts, int64_t p_size, const Dictionary &p_opentype_features) { - GDVIRTUAL_CALL(_shaped_set_span_update_font, p_shaped, p_index, p_fonts, p_size, p_opentype_features); + GDVIRTUAL_REQUIRED_CALL(_shaped_set_span_update_font, p_shaped, p_index, p_fonts, p_size, p_opentype_features); } RID TextServerExtension::shaped_text_substr(const RID &p_shaped, int64_t p_start, int64_t p_length) const { RID ret; - GDVIRTUAL_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_substr, p_shaped, p_start, p_length, ret); return ret; } RID TextServerExtension::shaped_text_get_parent(const RID &p_shaped) const { RID ret; - GDVIRTUAL_CALL(_shaped_text_get_parent, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_parent, p_shaped, ret); return ret; } @@ -1174,7 +1194,7 @@ double TextServerExtension::shaped_text_tab_align(const RID &p_shaped, const Pac bool TextServerExtension::shaped_text_shape(const RID &p_shaped) { bool ret = false; - GDVIRTUAL_CALL(_shaped_text_shape, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_shape, p_shaped, ret); return ret; } @@ -1192,31 +1212,31 @@ bool TextServerExtension::shaped_text_update_justification_ops(const RID &p_shap bool TextServerExtension::shaped_text_is_ready(const RID &p_shaped) const { bool ret = false; - GDVIRTUAL_CALL(_shaped_text_is_ready, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_is_ready, p_shaped, ret); return ret; } const Glyph *TextServerExtension::shaped_text_get_glyphs(const RID &p_shaped) const { GDExtensionConstPtr<const Glyph> ret; - GDVIRTUAL_CALL(_shaped_text_get_glyphs, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_glyphs, p_shaped, ret); return ret; } const Glyph *TextServerExtension::shaped_text_sort_logical(const RID &p_shaped) { GDExtensionConstPtr<const Glyph> ret; - GDVIRTUAL_CALL(_shaped_text_sort_logical, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_sort_logical, p_shaped, ret); return ret; } int64_t TextServerExtension::shaped_text_get_glyph_count(const RID &p_shaped) const { int64_t ret = 0; - GDVIRTUAL_CALL(_shaped_text_get_glyph_count, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_glyph_count, p_shaped, ret); return ret; } Vector2i TextServerExtension::shaped_text_get_range(const RID &p_shaped) const { Vector2i ret; - GDVIRTUAL_CALL(_shaped_text_get_range, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_range, p_shaped, ret); return ret; } @@ -1246,25 +1266,25 @@ PackedInt32Array TextServerExtension::shaped_text_get_word_breaks(const RID &p_s int64_t TextServerExtension::shaped_text_get_trim_pos(const RID &p_shaped) const { int64_t ret = -1; - GDVIRTUAL_CALL(_shaped_text_get_trim_pos, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_trim_pos, p_shaped, ret); return ret; } int64_t TextServerExtension::shaped_text_get_ellipsis_pos(const RID &p_shaped) const { int64_t ret = -1; - GDVIRTUAL_CALL(_shaped_text_get_ellipsis_pos, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_ellipsis_pos, p_shaped, ret); return ret; } const Glyph *TextServerExtension::shaped_text_get_ellipsis_glyphs(const RID &p_shaped) const { GDExtensionConstPtr<const Glyph> ret; - GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_ellipsis_glyphs, p_shaped, ret); return ret; } int64_t TextServerExtension::shaped_text_get_ellipsis_glyph_count(const RID &p_shaped) const { int64_t ret = -1; - GDVIRTUAL_CALL(_shaped_text_get_ellipsis_glyph_count, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_ellipsis_glyph_count, p_shaped, ret); return ret; } @@ -1274,49 +1294,61 @@ void TextServerExtension::shaped_text_overrun_trim_to_width(const RID &p_shaped_ Array TextServerExtension::shaped_text_get_objects(const RID &p_shaped) const { Array ret; - GDVIRTUAL_CALL(_shaped_text_get_objects, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_objects, p_shaped, ret); return ret; } Rect2 TextServerExtension::shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const { Rect2 ret; - GDVIRTUAL_CALL(_shaped_text_get_object_rect, p_shaped, p_key, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_object_rect, p_shaped, p_key, ret); + return ret; +} + +Vector2i TextServerExtension::shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const { + Vector2i ret; + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_object_range, p_shaped, p_key, ret); + return ret; +} + +int64_t TextServerExtension::shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const { + int64_t ret = -1; + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_object_glyph, p_shaped, p_key, ret); return ret; } Size2 TextServerExtension::shaped_text_get_size(const RID &p_shaped) const { Size2 ret; - GDVIRTUAL_CALL(_shaped_text_get_size, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_size, p_shaped, ret); return ret; } double TextServerExtension::shaped_text_get_ascent(const RID &p_shaped) const { double ret = 0; - GDVIRTUAL_CALL(_shaped_text_get_ascent, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_ascent, p_shaped, ret); return ret; } double TextServerExtension::shaped_text_get_descent(const RID &p_shaped) const { double ret = 0; - GDVIRTUAL_CALL(_shaped_text_get_descent, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_descent, p_shaped, ret); return ret; } double TextServerExtension::shaped_text_get_width(const RID &p_shaped) const { double ret = 0; - GDVIRTUAL_CALL(_shaped_text_get_width, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_width, p_shaped, ret); return ret; } double TextServerExtension::shaped_text_get_underline_position(const RID &p_shaped) const { double ret = 0; - GDVIRTUAL_CALL(_shaped_text_get_underline_position, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_underline_position, p_shaped, ret); return ret; } double TextServerExtension::shaped_text_get_underline_thickness(const RID &p_shaped) const { double ret = 0; - GDVIRTUAL_CALL(_shaped_text_get_underline_thickness, p_shaped, ret); + GDVIRTUAL_REQUIRED_CALL(_shaped_text_get_underline_thickness, p_shaped, ret); return ret; } @@ -1476,6 +1508,14 @@ String TextServerExtension::string_to_upper(const String &p_string, const String return p_string; } +String TextServerExtension::string_to_title(const String &p_string, const String &p_language) const { + String ret; + if (GDVIRTUAL_CALL(_string_to_title, p_string, p_language, ret)) { + return ret; + } + return p_string; +} + String TextServerExtension::string_to_lower(const String &p_string, const String &p_language) const { String ret; if (GDVIRTUAL_CALL(_string_to_lower, p_string, p_language, ret)) { @@ -1486,8 +1526,10 @@ String TextServerExtension::string_to_lower(const String &p_string, const String TypedArray<Vector3i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const { TypedArray<Vector3i> ret; - GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret); - return ret; + if (GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret)) { + return ret; + } + return TextServer::parse_structured_text(p_parser_type, p_args, p_text); } PackedInt32Array TextServerExtension::string_get_word_breaks(const String &p_string, const String &p_language, int64_t p_chars_per_line) const { diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h index 4f9ea55d33..53d30abee4 100644 --- a/servers/text/text_server_extension.h +++ b/servers/text/text_server_extension.h @@ -128,6 +128,11 @@ public: GDVIRTUAL2(_font_set_antialiasing, RID, TextServer::FontAntialiasing); GDVIRTUAL1RC(TextServer::FontAntialiasing, _font_get_antialiasing, RID); + virtual void font_set_disable_embedded_bitmaps(const RID &p_font_rid, bool p_disable_embedded_bitmaps) override; + virtual bool font_get_disable_embedded_bitmaps(const RID &p_font_rid) const override; + GDVIRTUAL2(_font_set_disable_embedded_bitmaps, RID, bool); + GDVIRTUAL1RC(bool, _font_get_disable_embedded_bitmaps, RID); + virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) override; virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const override; GDVIRTUAL2(_font_set_generate_mipmaps, RID, bool); @@ -486,8 +491,12 @@ public: virtual Array shaped_text_get_objects(const RID &p_shaped) const override; virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const override; + virtual Vector2i shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const override; + virtual int64_t shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const override; GDVIRTUAL1RC(Array, _shaped_text_get_objects, RID); GDVIRTUAL2RC(Rect2, _shaped_text_get_object_rect, RID, const Variant &); + GDVIRTUAL2RC(Vector2i, _shaped_text_get_object_range, RID, const Variant &); + GDVIRTUAL2RC(int64_t, _shaped_text_get_object_glyph, RID, const Variant &); virtual Size2 shaped_text_get_size(const RID &p_shaped) const override; virtual double shaped_text_get_ascent(const RID &p_shaped) const override; @@ -557,8 +566,10 @@ public: virtual String string_to_upper(const String &p_string, const String &p_language = "") const override; virtual String string_to_lower(const String &p_string, const String &p_language = "") const override; + virtual String string_to_title(const String &p_string, const String &p_language = "") const override; GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &); GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &); + GDVIRTUAL2RC(String, _string_to_title, const String &, const String &); TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &); diff --git a/servers/text_server.cpp b/servers/text_server.cpp index b67a698615..fac9e32d01 100644 --- a/servers/text_server.cpp +++ b/servers/text_server.cpp @@ -234,6 +234,9 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("font_set_antialiasing", "font_rid", "antialiasing"), &TextServer::font_set_antialiasing); ClassDB::bind_method(D_METHOD("font_get_antialiasing", "font_rid"), &TextServer::font_get_antialiasing); + ClassDB::bind_method(D_METHOD("font_set_disable_embedded_bitmaps", "font_rid", "disable_embedded_bitmaps"), &TextServer::font_set_disable_embedded_bitmaps); + ClassDB::bind_method(D_METHOD("font_get_disable_embedded_bitmaps", "font_rid"), &TextServer::font_get_disable_embedded_bitmaps); + ClassDB::bind_method(D_METHOD("font_set_generate_mipmaps", "font_rid", "generate_mipmaps"), &TextServer::font_set_generate_mipmaps); ClassDB::bind_method(D_METHOD("font_get_generate_mipmaps", "font_rid"), &TextServer::font_get_generate_mipmaps); @@ -443,6 +446,8 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("shaped_text_get_objects", "shaped"), &TextServer::shaped_text_get_objects); ClassDB::bind_method(D_METHOD("shaped_text_get_object_rect", "shaped", "key"), &TextServer::shaped_text_get_object_rect); + ClassDB::bind_method(D_METHOD("shaped_text_get_object_range", "shaped", "key"), &TextServer::shaped_text_get_object_range); + ClassDB::bind_method(D_METHOD("shaped_text_get_object_glyph", "shaped", "key"), &TextServer::shaped_text_get_object_glyph); ClassDB::bind_method(D_METHOD("shaped_text_get_size", "shaped"), &TextServer::shaped_text_get_size); ClassDB::bind_method(D_METHOD("shaped_text_get_ascent", "shaped"), &TextServer::shaped_text_get_ascent); @@ -486,6 +491,7 @@ void TextServer::_bind_methods() { ClassDB::bind_method(D_METHOD("string_to_upper", "string", "language"), &TextServer::string_to_upper, DEFVAL("")); ClassDB::bind_method(D_METHOD("string_to_lower", "string", "language"), &TextServer::string_to_lower, DEFVAL("")); + ClassDB::bind_method(D_METHOD("string_to_title", "string", "language"), &TextServer::string_to_title, DEFVAL("")); ClassDB::bind_method(D_METHOD("parse_structured_text", "parser_type", "args", "text"), &TextServer::parse_structured_text); @@ -535,6 +541,7 @@ void TextServer::_bind_methods() { BIND_BITFIELD_FLAG(BREAK_GRAPHEME_BOUND); BIND_BITFIELD_FLAG(BREAK_ADAPTIVE); BIND_BITFIELD_FLAG(BREAK_TRIM_EDGE_SPACES); + BIND_BITFIELD_FLAG(BREAK_TRIM_INDENT); /* VisibleCharactersBehavior */ BIND_ENUM_CONSTANT(VC_CHARS_BEFORE_SHAPING); @@ -636,6 +643,48 @@ void TextServer::_bind_methods() { BIND_ENUM_CONSTANT(FIXED_SIZE_SCALE_ENABLED); } +_FORCE_INLINE_ int32_t ot_tag_from_string(const char *p_str, int p_len) { + char tag[4]; + uint32_t i; + + if (!p_str || !p_len || !*p_str) { + return OT_TAG(0, 0, 0, 0); + } + + if (p_len < 0 || p_len > 4) { + p_len = 4; + } + for (i = 0; i < (uint32_t)p_len && p_str[i]; i++) { + tag[i] = p_str[i]; + } + + for (; i < 4; i++) { + tag[i] = ' '; + } + + return OT_TAG(tag[0], tag[1], tag[2], tag[3]); +} + +int64_t TextServer::name_to_tag(const String &p_name) const { + // No readable name, use tag string. + return ot_tag_from_string(p_name.replace("custom_", "").ascii().get_data(), -1); +} + +_FORCE_INLINE_ void ot_tag_to_string(int32_t p_tag, char *p_buf) { + p_buf[0] = (char)(uint8_t)(p_tag >> 24); + p_buf[1] = (char)(uint8_t)(p_tag >> 16); + p_buf[2] = (char)(uint8_t)(p_tag >> 8); + p_buf[3] = (char)(uint8_t)(p_tag >> 0); +} + +String TextServer::tag_to_name(int64_t p_tag) const { + // No readable name, use tag string. + char name[5]; + memset(name, 0, 5); + ot_tag_to_string(p_tag, name); + return String("custom_") + String(name); +} + Vector2 TextServer::get_hex_code_box_size(int64_t p_size, int64_t p_index) const { int w = ((p_index <= 0xFF) ? 1 : ((p_index <= 0xFFFF) ? 2 : 3)); int sp = MAX(0, w - 1); @@ -750,13 +799,28 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks_adv(const RID &p_shaped int l_size = shaped_text_get_glyph_count(p_shaped); const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + double indent = 0.0; + if (p_break_flags.has_flag(BREAK_TRIM_INDENT)) { + for (int i = 0; i < l_size; i++) { + if ((l_gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB || (l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { + indent += l_gl[i].advance * l_gl[i].repeat; + } else { + break; + } + } + } + for (int i = 0; i < l_size; i++) { + double l_width = p_width[chunk]; + if (l_width > indent) { + l_width -= indent; + } if (l_gl[i].start < p_start) { prev_safe_break = i + 1; continue; } if (l_gl[i].count > 0) { - if ((p_width[chunk] > 0) && (width + l_gl[i].advance > p_width[chunk]) && (last_safe_break >= 0)) { + if ((l_width > 0) && (width + l_gl[i].advance > l_width) && (last_safe_break >= 0)) { if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { int start_pos = prev_safe_break; int end_pos = last_safe_break; @@ -891,13 +955,25 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do int l_size = shaped_text_get_glyph_count(p_shaped); const Glyph *l_gl = const_cast<TextServer *>(this)->shaped_text_sort_logical(p_shaped); + double indent = 0.0; + if (p_break_flags.has_flag(BREAK_TRIM_INDENT)) { + for (int i = 0; i < l_size; i++) { + if ((l_gl[i].flags & GRAPHEME_IS_TAB) == GRAPHEME_IS_TAB || (l_gl[i].flags & GRAPHEME_IS_SPACE) == GRAPHEME_IS_SPACE) { + indent += l_gl[i].advance * l_gl[i].repeat; + } else { + break; + } + } + } + + double l_width = p_width; for (int i = 0; i < l_size; i++) { if (l_gl[i].start < p_start) { prev_safe_break = i + 1; continue; } 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)) { + if ((l_width > 0) && (width + l_gl[i].advance * l_gl[i].repeat > l_width) && (last_safe_break >= 0)) { if (p_break_flags.has_flag(BREAK_TRIM_EDGE_SPACES)) { int start_pos = prev_safe_break; int end_pos = last_safe_break; @@ -910,6 +986,9 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do if (last_end <= l_gl[start_pos].start) { lines.push_back(l_gl[start_pos].start); lines.push_back(l_gl[end_pos].end); + if (p_width > indent) { + l_width = p_width - indent; + } last_end = l_gl[end_pos].end; } trim_next = true; @@ -917,6 +996,9 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do if (last_end <= line_start) { lines.push_back(line_start); lines.push_back(l_gl[last_safe_break].end); + if (p_width > indent) { + l_width = p_width - indent; + } last_end = l_gl[last_safe_break].end; } } @@ -943,12 +1025,18 @@ PackedInt32Array TextServer::shaped_text_get_line_breaks(const RID &p_shaped, do if (last_end <= l_gl[start_pos].start) { lines.push_back(l_gl[start_pos].start); lines.push_back(l_gl[end_pos].end); + if (p_width > indent) { + l_width = p_width - indent; + } last_end = l_gl[end_pos].end; } } else { if (last_end <= line_start) { lines.push_back(line_start); lines.push_back(l_gl[i].end); + if (p_width > indent) { + l_width = p_width - indent; + } last_end = l_gl[i].end; } } diff --git a/servers/text_server.h b/servers/text_server.h index c2cc444646..396d7ca8e5 100644 --- a/servers/text_server.h +++ b/servers/text_server.h @@ -43,6 +43,8 @@ class TypedArray; struct Glyph; struct CaretInfo; +#define OT_TAG(m_c1, m_c2, m_c3, m_c4) ((int32_t)((((uint32_t)(m_c1) & 0xff) << 24) | (((uint32_t)(m_c2) & 0xff) << 16) | (((uint32_t)(m_c3) & 0xff) << 8) | ((uint32_t)(m_c4) & 0xff))) + class TextServer : public RefCounted { GDCLASS(TextServer, RefCounted); @@ -108,6 +110,7 @@ public: BREAK_GRAPHEME_BOUND = 1 << 2, BREAK_ADAPTIVE = 1 << 3, BREAK_TRIM_EDGE_SPACES = 1 << 4, + BREAK_TRIM_INDENT = 1 << 5, }; enum OverrunBehavior { @@ -238,8 +241,8 @@ public: virtual bool is_locale_right_to_left(const String &p_locale) const = 0; - virtual int64_t name_to_tag(const String &p_name) const { return 0; }; - virtual String tag_to_name(int64_t p_tag) const { return ""; }; + virtual int64_t name_to_tag(const String &p_name) const; + virtual String tag_to_name(int64_t p_tag) const; /* Font interface */ @@ -273,6 +276,9 @@ public: virtual void font_set_antialiasing(const RID &p_font_rid, FontAntialiasing p_antialiasing) = 0; virtual FontAntialiasing font_get_antialiasing(const RID &p_font_rid) const = 0; + virtual void font_set_disable_embedded_bitmaps(const RID &p_font_rid, bool p_disable_embedded_bitmaps) = 0; + virtual bool font_get_disable_embedded_bitmaps(const RID &p_font_rid) const = 0; + virtual void font_set_generate_mipmaps(const RID &p_font_rid, bool p_generate_mipmaps) = 0; virtual bool font_get_generate_mipmaps(const RID &p_font_rid) const = 0; @@ -489,6 +495,8 @@ public: virtual Array shaped_text_get_objects(const RID &p_shaped) const = 0; virtual Rect2 shaped_text_get_object_rect(const RID &p_shaped, const Variant &p_key) const = 0; + virtual Vector2i shaped_text_get_object_range(const RID &p_shaped, const Variant &p_key) const = 0; + virtual int64_t shaped_text_get_object_glyph(const RID &p_shaped, const Variant &p_key) const = 0; virtual Size2 shaped_text_get_size(const RID &p_shaped) const = 0; virtual double shaped_text_get_ascent(const RID &p_shaped) const = 0; @@ -538,6 +546,7 @@ public: // Other string operations. virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0; virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0; + virtual String string_to_title(const String &p_string, const String &p_language = "") const = 0; TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const; diff --git a/servers/xr/xr_body_tracker.cpp b/servers/xr/xr_body_tracker.cpp new file mode 100644 index 0000000000..cd58c14348 --- /dev/null +++ b/servers/xr/xr_body_tracker.cpp @@ -0,0 +1,171 @@ +/**************************************************************************/ +/* xr_body_tracker.cpp */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_body_tracker.h" + +void XRBodyTracker::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_has_tracking_data", "has_data"), &XRBodyTracker::set_has_tracking_data); + ClassDB::bind_method(D_METHOD("get_has_tracking_data"), &XRBodyTracker::get_has_tracking_data); + + ClassDB::bind_method(D_METHOD("set_body_flags", "flags"), &XRBodyTracker::set_body_flags); + ClassDB::bind_method(D_METHOD("get_body_flags"), &XRBodyTracker::get_body_flags); + + ClassDB::bind_method(D_METHOD("set_joint_flags", "joint", "flags"), &XRBodyTracker::set_joint_flags); + ClassDB::bind_method(D_METHOD("get_joint_flags", "joint"), &XRBodyTracker::get_joint_flags); + + ClassDB::bind_method(D_METHOD("set_joint_transform", "joint", "transform"), &XRBodyTracker::set_joint_transform); + ClassDB::bind_method(D_METHOD("get_joint_transform", "joint"), &XRBodyTracker::get_joint_transform); + + ADD_PROPERTY(PropertyInfo(Variant::BOOL, "has_tracking_data", PROPERTY_HINT_NONE), "set_has_tracking_data", "get_has_tracking_data"); + ADD_PROPERTY(PropertyInfo(Variant::INT, "body_flags", PROPERTY_HINT_FLAGS, "Upper Body,Lower Body,Hands"), "set_body_flags", "get_body_flags"); + + BIND_BITFIELD_FLAG(BODY_FLAG_UPPER_BODY_SUPPORTED); + BIND_BITFIELD_FLAG(BODY_FLAG_LOWER_BODY_SUPPORTED); + BIND_BITFIELD_FLAG(BODY_FLAG_HANDS_SUPPORTED); + + BIND_ENUM_CONSTANT(JOINT_ROOT); + BIND_ENUM_CONSTANT(JOINT_HIPS); + BIND_ENUM_CONSTANT(JOINT_SPINE); + BIND_ENUM_CONSTANT(JOINT_CHEST); + BIND_ENUM_CONSTANT(JOINT_UPPER_CHEST); + BIND_ENUM_CONSTANT(JOINT_NECK); + BIND_ENUM_CONSTANT(JOINT_HEAD); + BIND_ENUM_CONSTANT(JOINT_HEAD_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_SHOULDER); + BIND_ENUM_CONSTANT(JOINT_LEFT_UPPER_ARM); + BIND_ENUM_CONSTANT(JOINT_LEFT_LOWER_ARM); + BIND_ENUM_CONSTANT(JOINT_RIGHT_SHOULDER); + BIND_ENUM_CONSTANT(JOINT_RIGHT_UPPER_ARM); + BIND_ENUM_CONSTANT(JOINT_RIGHT_LOWER_ARM); + BIND_ENUM_CONSTANT(JOINT_LEFT_UPPER_LEG); + BIND_ENUM_CONSTANT(JOINT_LEFT_LOWER_LEG); + BIND_ENUM_CONSTANT(JOINT_LEFT_FOOT); + BIND_ENUM_CONSTANT(JOINT_LEFT_TOES); + BIND_ENUM_CONSTANT(JOINT_RIGHT_UPPER_LEG); + BIND_ENUM_CONSTANT(JOINT_RIGHT_LOWER_LEG); + BIND_ENUM_CONSTANT(JOINT_RIGHT_FOOT); + BIND_ENUM_CONSTANT(JOINT_RIGHT_TOES); + BIND_ENUM_CONSTANT(JOINT_LEFT_HAND); + BIND_ENUM_CONSTANT(JOINT_LEFT_PALM); + BIND_ENUM_CONSTANT(JOINT_LEFT_WRIST); + BIND_ENUM_CONSTANT(JOINT_LEFT_THUMB_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_THUMB_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_THUMB_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_THUMB_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_INDEX_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_MIDDLE_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_RING_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_LEFT_PINKY_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_HAND); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PALM); + BIND_ENUM_CONSTANT(JOINT_RIGHT_WRIST); + BIND_ENUM_CONSTANT(JOINT_RIGHT_THUMB_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_THUMB_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_THUMB_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_THUMB_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_INDEX_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_MIDDLE_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_RING_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_METACARPAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_PHALANX_PROXIMAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_PHALANX_INTERMEDIATE); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_PHALANX_DISTAL); + BIND_ENUM_CONSTANT(JOINT_RIGHT_PINKY_FINGER_TIP); + BIND_ENUM_CONSTANT(JOINT_MAX); + + BIND_BITFIELD_FLAG(JOINT_FLAG_ORIENTATION_VALID); + BIND_BITFIELD_FLAG(JOINT_FLAG_ORIENTATION_TRACKED); + BIND_BITFIELD_FLAG(JOINT_FLAG_POSITION_VALID); + BIND_BITFIELD_FLAG(JOINT_FLAG_POSITION_TRACKED); +} + +void XRBodyTracker::set_has_tracking_data(bool p_has_tracking_data) { + has_tracking_data = p_has_tracking_data; +} + +bool XRBodyTracker::get_has_tracking_data() const { + return has_tracking_data; +} + +void XRBodyTracker::set_body_flags(BitField<BodyFlags> p_body_flags) { + body_flags = p_body_flags; +} + +BitField<XRBodyTracker::BodyFlags> XRBodyTracker::get_body_flags() const { + return body_flags; +} + +void XRBodyTracker::set_joint_flags(Joint p_joint, BitField<JointFlags> p_flags) { + ERR_FAIL_INDEX(p_joint, JOINT_MAX); + joint_flags[p_joint] = p_flags; +} + +BitField<XRBodyTracker::JointFlags> XRBodyTracker::get_joint_flags(Joint p_joint) const { + ERR_FAIL_INDEX_V(p_joint, JOINT_MAX, BitField<JointFlags>()); + return joint_flags[p_joint]; +} + +void XRBodyTracker::set_joint_transform(Joint p_joint, const Transform3D &p_transform) { + ERR_FAIL_INDEX(p_joint, JOINT_MAX); + joint_transforms[p_joint] = p_transform; +} + +Transform3D XRBodyTracker::get_joint_transform(Joint p_joint) const { + ERR_FAIL_INDEX_V(p_joint, JOINT_MAX, Transform3D()); + return joint_transforms[p_joint]; +} diff --git a/servers/xr/xr_body_tracker.h b/servers/xr/xr_body_tracker.h new file mode 100644 index 0000000000..659aa39df1 --- /dev/null +++ b/servers/xr/xr_body_tracker.h @@ -0,0 +1,170 @@ +/**************************************************************************/ +/* xr_body_tracker.h */ +/**************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/**************************************************************************/ +/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ +/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ +/* */ +/* 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_BODY_TRACKER_H +#define XR_BODY_TRACKER_H + +#include "core/object/ref_counted.h" + +class XRBodyTracker : public RefCounted { + GDCLASS(XRBodyTracker, RefCounted); + _THREAD_SAFE_CLASS_ + +public: + enum BodyFlags { + BODY_FLAG_UPPER_BODY_SUPPORTED = 1, + BODY_FLAG_LOWER_BODY_SUPPORTED = 2, + BODY_FLAG_HANDS_SUPPORTED = 4, + }; + + enum Joint { + JOINT_ROOT, + + // Upper Body Joints + JOINT_HIPS, + JOINT_SPINE, + JOINT_CHEST, + JOINT_UPPER_CHEST, + JOINT_NECK, + JOINT_HEAD, + JOINT_HEAD_TIP, + JOINT_LEFT_SHOULDER, + JOINT_LEFT_UPPER_ARM, + JOINT_LEFT_LOWER_ARM, + JOINT_RIGHT_SHOULDER, + JOINT_RIGHT_UPPER_ARM, + JOINT_RIGHT_LOWER_ARM, + + // Lower Body Joints + JOINT_LEFT_UPPER_LEG, + JOINT_LEFT_LOWER_LEG, + JOINT_LEFT_FOOT, + JOINT_LEFT_TOES, + JOINT_RIGHT_UPPER_LEG, + JOINT_RIGHT_LOWER_LEG, + JOINT_RIGHT_FOOT, + JOINT_RIGHT_TOES, + + // Left Hand Joints + JOINT_LEFT_HAND, + JOINT_LEFT_PALM, + JOINT_LEFT_WRIST, + JOINT_LEFT_THUMB_METACARPAL, + JOINT_LEFT_THUMB_PHALANX_PROXIMAL, + JOINT_LEFT_THUMB_PHALANX_DISTAL, + JOINT_LEFT_THUMB_TIP, + JOINT_LEFT_INDEX_FINGER_METACARPAL, + JOINT_LEFT_INDEX_FINGER_PHALANX_PROXIMAL, + JOINT_LEFT_INDEX_FINGER_PHALANX_INTERMEDIATE, + JOINT_LEFT_INDEX_FINGER_PHALANX_DISTAL, + JOINT_LEFT_INDEX_FINGER_TIP, + JOINT_LEFT_MIDDLE_FINGER_METACARPAL, + JOINT_LEFT_MIDDLE_FINGER_PHALANX_PROXIMAL, + JOINT_LEFT_MIDDLE_FINGER_PHALANX_INTERMEDIATE, + JOINT_LEFT_MIDDLE_FINGER_PHALANX_DISTAL, + JOINT_LEFT_MIDDLE_FINGER_TIP, + JOINT_LEFT_RING_FINGER_METACARPAL, + JOINT_LEFT_RING_FINGER_PHALANX_PROXIMAL, + JOINT_LEFT_RING_FINGER_PHALANX_INTERMEDIATE, + JOINT_LEFT_RING_FINGER_PHALANX_DISTAL, + JOINT_LEFT_RING_FINGER_TIP, + JOINT_LEFT_PINKY_FINGER_METACARPAL, + JOINT_LEFT_PINKY_FINGER_PHALANX_PROXIMAL, + JOINT_LEFT_PINKY_FINGER_PHALANX_INTERMEDIATE, + JOINT_LEFT_PINKY_FINGER_PHALANX_DISTAL, + JOINT_LEFT_PINKY_FINGER_TIP, + + // Right Hand Joints + JOINT_RIGHT_HAND, + JOINT_RIGHT_PALM, + JOINT_RIGHT_WRIST, + JOINT_RIGHT_THUMB_METACARPAL, + JOINT_RIGHT_THUMB_PHALANX_PROXIMAL, + JOINT_RIGHT_THUMB_PHALANX_DISTAL, + JOINT_RIGHT_THUMB_TIP, + JOINT_RIGHT_INDEX_FINGER_METACARPAL, + JOINT_RIGHT_INDEX_FINGER_PHALANX_PROXIMAL, + JOINT_RIGHT_INDEX_FINGER_PHALANX_INTERMEDIATE, + JOINT_RIGHT_INDEX_FINGER_PHALANX_DISTAL, + JOINT_RIGHT_INDEX_FINGER_TIP, + JOINT_RIGHT_MIDDLE_FINGER_METACARPAL, + JOINT_RIGHT_MIDDLE_FINGER_PHALANX_PROXIMAL, + JOINT_RIGHT_MIDDLE_FINGER_PHALANX_INTERMEDIATE, + JOINT_RIGHT_MIDDLE_FINGER_PHALANX_DISTAL, + JOINT_RIGHT_MIDDLE_FINGER_TIP, + JOINT_RIGHT_RING_FINGER_METACARPAL, + JOINT_RIGHT_RING_FINGER_PHALANX_PROXIMAL, + JOINT_RIGHT_RING_FINGER_PHALANX_INTERMEDIATE, + JOINT_RIGHT_RING_FINGER_PHALANX_DISTAL, + JOINT_RIGHT_RING_FINGER_TIP, + JOINT_RIGHT_PINKY_FINGER_METACARPAL, + JOINT_RIGHT_PINKY_FINGER_PHALANX_PROXIMAL, + JOINT_RIGHT_PINKY_FINGER_PHALANX_INTERMEDIATE, + JOINT_RIGHT_PINKY_FINGER_PHALANX_DISTAL, + JOINT_RIGHT_PINKY_FINGER_TIP, + + JOINT_MAX, + }; + + enum JointFlags { + JOINT_FLAG_ORIENTATION_VALID = 1, + JOINT_FLAG_ORIENTATION_TRACKED = 2, + JOINT_FLAG_POSITION_VALID = 4, + JOINT_FLAG_POSITION_TRACKED = 8, + }; + + void set_has_tracking_data(bool p_has_tracking_data); + bool get_has_tracking_data() const; + + void set_body_flags(BitField<BodyFlags> p_body_flags); + BitField<BodyFlags> get_body_flags() const; + + void set_joint_flags(Joint p_joint, BitField<JointFlags> p_flags); + BitField<JointFlags> get_joint_flags(Joint p_joint) const; + + void set_joint_transform(Joint p_joint, const Transform3D &p_transform); + Transform3D get_joint_transform(Joint p_joint) const; + +protected: + static void _bind_methods(); + +private: + bool has_tracking_data = false; + BitField<BodyFlags> body_flags; + + BitField<JointFlags> joint_flags[JOINT_MAX]; + Transform3D joint_transforms[JOINT_MAX]; +}; + +VARIANT_BITFIELD_CAST(XRBodyTracker::BodyFlags) +VARIANT_ENUM_CAST(XRBodyTracker::Joint) +VARIANT_BITFIELD_CAST(XRBodyTracker::JointFlags) + +#endif // XR_BODY_TRACKER_H diff --git a/servers/xr_server.cpp b/servers/xr_server.cpp index 1e497e22c3..af14ba4a00 100644 --- a/servers/xr_server.cpp +++ b/servers/xr_server.cpp @@ -30,6 +30,7 @@ #include "xr_server.h" #include "core/config/project_settings.h" +#include "xr/xr_body_tracker.h" #include "xr/xr_face_tracker.h" #include "xr/xr_hand_tracker.h" #include "xr/xr_interface.h" @@ -86,6 +87,11 @@ void XRServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_face_trackers"), &XRServer::get_face_trackers); ClassDB::bind_method(D_METHOD("get_face_tracker", "tracker_name"), &XRServer::get_face_tracker); + ClassDB::bind_method(D_METHOD("add_body_tracker", "tracker_name", "body_tracker"), &XRServer::add_body_tracker); + ClassDB::bind_method(D_METHOD("remove_body_tracker", "tracker_name"), &XRServer::remove_body_tracker); + ClassDB::bind_method(D_METHOD("get_body_trackers"), &XRServer::get_body_trackers); + ClassDB::bind_method(D_METHOD("get_body_tracker", "tracker_name"), &XRServer::get_body_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); @@ -117,6 +123,10 @@ void XRServer::_bind_methods() { ADD_SIGNAL(MethodInfo("face_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "face_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRFaceTracker"))); ADD_SIGNAL(MethodInfo("face_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "face_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRFaceTracker"))); ADD_SIGNAL(MethodInfo("face_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); + + ADD_SIGNAL(MethodInfo("body_tracker_added", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "body_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRBodyTracker"))); + ADD_SIGNAL(MethodInfo("body_tracker_updated", PropertyInfo(Variant::STRING_NAME, "tracker_name"), PropertyInfo(Variant::OBJECT, "body_tracker", PROPERTY_HINT_RESOURCE_TYPE, "XRBodyTracker"))); + ADD_SIGNAL(MethodInfo("body_tracker_removed", PropertyInfo(Variant::STRING_NAME, "tracker_name"))); }; double XRServer::get_world_scale() const { @@ -448,6 +458,44 @@ Ref<XRFaceTracker> XRServer::get_face_tracker(const StringName &p_tracker_name) return face_trackers[p_tracker_name]; } +void XRServer::add_body_tracker(const StringName &p_tracker_name, Ref<XRBodyTracker> p_body_tracker) { + ERR_FAIL_COND(p_body_tracker.is_null()); + + if (!body_trackers.has(p_tracker_name)) { + // We don't have a tracker with this name, we're going to add it. + body_trackers[p_tracker_name] = p_body_tracker; + emit_signal(SNAME("body_tracker_added"), p_tracker_name, p_body_tracker); + } else if (body_trackers[p_tracker_name] != p_body_tracker) { + // We already have a tracker with this name, we're going to replace it. + body_trackers[p_tracker_name] = p_body_tracker; + emit_signal(SNAME("body_tracker_updated"), p_tracker_name, p_body_tracker); + } +} + +void XRServer::remove_body_tracker(const StringName &p_tracker_name) { + // Skip if no face tracker is found. + if (!body_trackers.has(p_tracker_name)) { + return; + } + + // Send the removed signal, then remove the face tracker. + emit_signal(SNAME("body_tracker_removed"), p_tracker_name); + body_trackers.erase(p_tracker_name); +} + +Dictionary XRServer::get_body_trackers() const { + return body_trackers; +} + +Ref<XRBodyTracker> XRServer::get_body_tracker(const StringName &p_tracker_name) const { + // Skip if no tracker is found. + if (!body_trackers.has(p_tracker_name)) { + return Ref<XRBodyTracker>(); + } + + return body_trackers[p_tracker_name]; +} + void XRServer::_process() { // called from our main game loop before we handle physics and game logic // note that we can have multiple interfaces active if we have interfaces that purely handle tracking diff --git a/servers/xr_server.h b/servers/xr_server.h index 3e45bbb76c..6aaa34b21d 100644 --- a/servers/xr_server.h +++ b/servers/xr_server.h @@ -41,6 +41,7 @@ class XRInterface; class XRPositionalTracker; class XRHandTracker; class XRFaceTracker; +class XRBodyTracker; /** The XR server is a singleton object that gives access to the various @@ -89,6 +90,7 @@ private: Dictionary trackers; Dictionary hand_trackers; Dictionary face_trackers; + Dictionary body_trackers; Ref<XRInterface> primary_interface; /* we'll identify one interface as primary, this will be used by our viewports */ @@ -203,6 +205,14 @@ public: Dictionary get_face_trackers() const; Ref<XRFaceTracker> get_face_tracker(const StringName &p_tracker_name) const; + /* + Body trackers are objects that expose the tracked joints of a body. + */ + void add_body_tracker(const StringName &p_tracker_name, Ref<XRBodyTracker> p_face_tracker); + void remove_body_tracker(const StringName &p_tracker_name); + Dictionary get_body_trackers() const; + Ref<XRBodyTracker> get_body_tracker(const StringName &p_tracker_name) const; + // Process is called before we handle our physics process and game process. This is where our interfaces will update controller data and such. void _process(); |