summaryrefslogtreecommitdiff
path: root/servers
diff options
context:
space:
mode:
Diffstat (limited to 'servers')
-rw-r--r--servers/arvr/arvr_interface.cpp5
-rw-r--r--servers/arvr/arvr_interface.h2
-rw-r--r--servers/arvr/arvr_positional_tracker.cpp15
-rw-r--r--servers/arvr/arvr_positional_tracker.h7
-rw-r--r--servers/audio/audio_rb_resampler.cpp6
-rw-r--r--servers/audio/effects/audio_effect_record.cpp2
-rw-r--r--servers/audio/effects/audio_effect_spectrum_analyzer.cpp256
-rw-r--r--servers/audio/effects/audio_effect_spectrum_analyzer.h76
-rw-r--r--servers/audio/effects/audio_stream_generator.cpp182
-rw-r--r--servers/audio/effects/audio_stream_generator.h66
-rw-r--r--servers/audio_server.cpp58
-rw-r--r--servers/audio_server.h15
-rw-r--r--servers/physics/body_sw.cpp9
-rw-r--r--servers/physics/collision_object_sw.cpp3
-rw-r--r--servers/physics/collision_object_sw.h2
-rw-r--r--servers/physics/collision_solver_sat.cpp6
-rw-r--r--servers/physics/joints/cone_twist_joint_sw.cpp6
-rw-r--r--servers/physics/joints/generic_6dof_joint_sw.cpp2
-rw-r--r--servers/physics/joints/hinge_joint_sw.cpp6
-rw-r--r--servers/physics/physics_server_sw.cpp8
-rw-r--r--servers/physics/physics_server_sw.h4
-rw-r--r--servers/physics/space_sw.cpp6
-rw-r--r--servers/physics_2d/body_2d_sw.cpp9
-rw-r--r--servers/physics_2d/collision_object_2d_sw.cpp4
-rw-r--r--servers/physics_2d/collision_object_2d_sw.h2
-rw-r--r--servers/physics_2d/collision_solver_2d_sat.cpp4
-rw-r--r--servers/physics_2d/joints_2d_sw.cpp4
-rw-r--r--servers/physics_2d/physics_2d_server_sw.cpp8
-rw-r--r--servers/physics_2d/physics_2d_server_sw.h4
-rw-r--r--servers/physics_2d/physics_2d_server_wrap_mt.h4
-rw-r--r--servers/physics_2d/shape_2d_sw.cpp2
-rw-r--r--servers/physics_2d/space_2d_sw.cpp8
-rw-r--r--servers/physics_2d_server.cpp8
-rw-r--r--servers/physics_2d_server.h10
-rw-r--r--servers/physics_server.cpp6
-rw-r--r--servers/physics_server.h10
-rw-r--r--servers/register_server_types.cpp10
-rw-r--r--servers/visual/rasterizer.h7
-rw-r--r--servers/visual/shader_language.cpp6
-rw-r--r--servers/visual/visual_server_canvas.cpp69
-rw-r--r--servers/visual/visual_server_canvas.h17
-rw-r--r--servers/visual/visual_server_raster.h6
-rw-r--r--servers/visual/visual_server_scene.cpp56
-rw-r--r--servers/visual/visual_server_scene.h6
-rw-r--r--servers/visual/visual_server_viewport.cpp86
-rw-r--r--servers/visual/visual_server_viewport.h1
-rw-r--r--servers/visual/visual_server_wrap_mt.h6
-rw-r--r--servers/visual_server.cpp2
-rw-r--r--servers/visual_server.h7
49 files changed, 944 insertions, 160 deletions
diff --git a/servers/arvr/arvr_interface.cpp b/servers/arvr/arvr_interface.cpp
index 3e59daff6c..686ad0ba9b 100644
--- a/servers/arvr/arvr_interface.cpp
+++ b/servers/arvr/arvr_interface.cpp
@@ -123,6 +123,11 @@ ARVRInterface::ARVRInterface() {
ARVRInterface::~ARVRInterface(){};
+// optional render to external texture which enhances performance on those platforms that require us to submit our end result into special textures.
+unsigned int ARVRInterface::get_external_texture_for_eye(ARVRInterface::Eyes p_eye) {
+ return 0;
+};
+
/** these will only be implemented on AR interfaces, so we want dummies for VR **/
bool ARVRInterface::get_anchor_detection_is_enabled() const {
return false;
diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h
index 6908f3006a..9ea59a3961 100644
--- a/servers/arvr/arvr_interface.h
+++ b/servers/arvr/arvr_interface.h
@@ -108,9 +108,11 @@ public:
virtual bool is_stereo() = 0; /* returns true if this interface requires stereo rendering (for VR HMDs) or mono rendering (for mobile AR) */
virtual Transform get_transform_for_eye(ARVRInterface::Eyes p_eye, const Transform &p_cam_transform) = 0; /* get each eyes camera transform, also implement EYE_MONO */
virtual CameraMatrix get_projection_for_eye(ARVRInterface::Eyes p_eye, real_t p_aspect, real_t p_z_near, real_t p_z_far) = 0; /* get each eyes projection matrix */
+ virtual unsigned int get_external_texture_for_eye(ARVRInterface::Eyes p_eye); /* if applicable return external texture to render to */
virtual void commit_for_eye(ARVRInterface::Eyes p_eye, RID p_render_target, const Rect2 &p_screen_rect) = 0; /* output the left or right eye */
virtual void process() = 0;
+ virtual void notification(int p_what) = 0;
ARVRInterface();
~ARVRInterface();
diff --git a/servers/arvr/arvr_positional_tracker.cpp b/servers/arvr/arvr_positional_tracker.cpp
index b96e9596f3..aabe617a8a 100644
--- a/servers/arvr/arvr_positional_tracker.cpp
+++ b/servers/arvr/arvr_positional_tracker.cpp
@@ -46,6 +46,7 @@ void ARVRPositionalTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_position"), &ARVRPositionalTracker::get_position);
ClassDB::bind_method(D_METHOD("get_hand"), &ARVRPositionalTracker::get_hand);
ClassDB::bind_method(D_METHOD("get_transform", "adjust_by_reference_frame"), &ARVRPositionalTracker::get_transform);
+ ClassDB::bind_method(D_METHOD("get_mesh"), &ARVRPositionalTracker::get_mesh);
// these functions we don't want to expose to normal users but do need to be callable from GDNative
ClassDB::bind_method(D_METHOD("_set_type", "type"), &ARVRPositionalTracker::set_type);
@@ -53,7 +54,7 @@ void ARVRPositionalTracker::_bind_methods() {
ClassDB::bind_method(D_METHOD("_set_joy_id", "joy_id"), &ARVRPositionalTracker::set_joy_id);
ClassDB::bind_method(D_METHOD("_set_orientation", "orientation"), &ARVRPositionalTracker::set_orientation);
ClassDB::bind_method(D_METHOD("_set_rw_position", "rw_position"), &ARVRPositionalTracker::set_rw_position);
-
+ ClassDB::bind_method(D_METHOD("_set_mesh", "mesh"), &ARVRPositionalTracker::set_mesh);
ClassDB::bind_method(D_METHOD("get_rumble"), &ARVRPositionalTracker::get_rumble);
ClassDB::bind_method(D_METHOD("set_rumble", "rumble"), &ARVRPositionalTracker::set_rumble);
@@ -154,6 +155,18 @@ Vector3 ARVRPositionalTracker::get_rw_position() const {
return rw_position;
};
+void ARVRPositionalTracker::set_mesh(const Ref<Mesh> &p_mesh) {
+ _THREAD_SAFE_METHOD_
+
+ mesh = p_mesh;
+};
+
+Ref<Mesh> ARVRPositionalTracker::get_mesh() const {
+ _THREAD_SAFE_METHOD_
+
+ return mesh;
+};
+
ARVRPositionalTracker::TrackerHand ARVRPositionalTracker::get_hand() const {
return hand;
};
diff --git a/servers/arvr/arvr_positional_tracker.h b/servers/arvr/arvr_positional_tracker.h
index 7cb9486f59..0d6a69540f 100644
--- a/servers/arvr/arvr_positional_tracker.h
+++ b/servers/arvr/arvr_positional_tracker.h
@@ -32,6 +32,7 @@
#define ARVR_POSITIONAL_TRACKER_H
#include "core/os/thread_safe.h"
+#include "scene/resources/mesh.h"
#include "servers/arvr_server.h"
/**
@@ -40,9 +41,6 @@
The positional tracker object as an object that represents the position and orientation of a tracked object like a controller or headset.
An AR/VR Interface will registered the trackers it manages with our AR/VR server and update its position and orientation.
This is where potentially additional AR/VR interfaces may be active as there are AR/VR SDKs that solely deal with positional tracking.
-
- @TODO:
- - create subclass of spatial node that uses one of our positional trackers to automatically determine its position
*/
class ARVRPositionalTracker : public Object {
@@ -65,6 +63,7 @@ private:
Basis orientation; // our orientation
bool tracks_position; // do we track position?
Vector3 rw_position; // our position "in the real world, so without world_scale applied"
+ Ref<Mesh> mesh; // when available, a mesh that can be used to render this tracker
TrackerHand hand; // if known, the hand this tracker is held in
real_t rumble; // rumble strength, 0.0 is off, 1.0 is maximum, note that we only record here, arvr_interface is responsible for execution
@@ -91,6 +90,8 @@ public:
void set_hand(const ARVRPositionalTracker::TrackerHand p_hand);
real_t get_rumble() const;
void set_rumble(real_t p_rumble);
+ void set_mesh(const Ref<Mesh> &p_mesh);
+ Ref<Mesh> get_mesh() const;
Transform get_transform(bool p_adjust_by_reference_frame) const;
diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp
index 88f3ed8d15..ad5bcde382 100644
--- a/servers/audio/audio_rb_resampler.cpp
+++ b/servers/audio/audio_rb_resampler.cpp
@@ -201,10 +201,8 @@ void AudioRBResampler::clear() {
return;
//should be stopped at this point but just in case
- if (rb) {
- memdelete_arr(rb);
- memdelete_arr(read_buf);
- }
+ memdelete_arr(rb);
+ memdelete_arr(read_buf);
rb = NULL;
offset = 0;
rb_read_pos = 0;
diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp
index 2dd71f9452..96d5c9df89 100644
--- a/servers/audio/effects/audio_effect_record.cpp
+++ b/servers/audio/effects/audio_effect_record.cpp
@@ -66,7 +66,7 @@ void AudioEffectRecordInstance::_io_thread_process() {
while (is_recording) {
//Check: The current recording has been requested to stop
- if (is_recording && !base->recording_active) {
+ if (!base->recording_active) {
is_recording = false;
}
diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.cpp b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp
new file mode 100644
index 0000000000..46d92336f3
--- /dev/null
+++ b/servers/audio/effects/audio_effect_spectrum_analyzer.cpp
@@ -0,0 +1,256 @@
+#include "audio_effect_spectrum_analyzer.h"
+#include "servers/audio_server.h"
+
+static void smbFft(float *fftBuffer, long fftFrameSize, long sign)
+/*
+ FFT routine, (C)1996 S.M.Bernsee. Sign = -1 is FFT, 1 is iFFT (inverse)
+ Fills fftBuffer[0...2*fftFrameSize-1] with the Fourier transform of the
+ time domain data in fftBuffer[0...2*fftFrameSize-1]. The FFT array takes
+ and returns the cosine and sine parts in an interleaved manner, ie.
+ fftBuffer[0] = cosPart[0], fftBuffer[1] = sinPart[0], asf. fftFrameSize
+ must be a power of 2. It expects a complex input signal (see footnote 2),
+ ie. when working with 'common' audio signals our input signal has to be
+ passed as {in[0],0.,in[1],0.,in[2],0.,...} asf. In that case, the transform
+ of the frequencies of interest is in fftBuffer[0...fftFrameSize].
+*/
+{
+ float wr, wi, arg, *p1, *p2, temp;
+ float tr, ti, ur, ui, *p1r, *p1i, *p2r, *p2i;
+ long i, bitm, j, le, le2, k;
+
+ for (i = 2; i < 2 * fftFrameSize - 2; i += 2) {
+ for (bitm = 2, j = 0; bitm < 2 * fftFrameSize; bitm <<= 1) {
+ if (i & bitm) j++;
+ j <<= 1;
+ }
+ if (i < j) {
+ p1 = fftBuffer + i;
+ p2 = fftBuffer + j;
+ temp = *p1;
+ *(p1++) = *p2;
+ *(p2++) = temp;
+ temp = *p1;
+ *p1 = *p2;
+ *p2 = temp;
+ }
+ }
+ for (k = 0, le = 2; k < (long)(log((double)fftFrameSize) / log(2.) + .5); k++) {
+ le <<= 1;
+ le2 = le >> 1;
+ ur = 1.0;
+ ui = 0.0;
+ arg = Math_PI / (le2 >> 1);
+ wr = cos(arg);
+ wi = sign * sin(arg);
+ for (j = 0; j < le2; j += 2) {
+ p1r = fftBuffer + j;
+ p1i = p1r + 1;
+ p2r = p1r + le2;
+ p2i = p2r + 1;
+ for (i = j; i < 2 * fftFrameSize; i += le) {
+ tr = *p2r * ur - *p2i * ui;
+ ti = *p2r * ui + *p2i * ur;
+ *p2r = *p1r - tr;
+ *p2i = *p1i - ti;
+ *p1r += tr;
+ *p1i += ti;
+ p1r += le;
+ p1i += le;
+ p2r += le;
+ p2i += le;
+ }
+ tr = ur * wr - ui * wi;
+ ui = ur * wi + ui * wr;
+ ur = tr;
+ }
+ }
+}
+void AudioEffectSpectrumAnalyzerInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) {
+
+ uint64_t time = OS::get_singleton()->get_ticks_usec();
+
+ //copy everything over first, since this only really does capture
+ for (int i = 0; i < p_frame_count; i++) {
+ p_dst_frames[i] = p_src_frames[i];
+ }
+
+ //capture spectrum
+ while (p_frame_count) {
+ int to_fill = fft_size * 2 - temporal_fft_pos;
+ to_fill = MIN(to_fill, p_frame_count);
+
+ float *fftw = temporal_fft.ptrw();
+ for (int i = 0; i < to_fill; i++) { //left and right buffers
+ fftw[(i + temporal_fft_pos) * 2] = p_src_frames[i].l;
+ fftw[(i + temporal_fft_pos) * 2 + 1] = 0;
+ fftw[(i + temporal_fft_pos + fft_size * 2) * 2] = p_src_frames[i].r;
+ fftw[(i + temporal_fft_pos + fft_size * 2) * 2 + 1] = 0;
+ }
+
+ p_src_frames += to_fill;
+ temporal_fft_pos += to_fill;
+ p_frame_count -= to_fill;
+
+ if (temporal_fft_pos == fft_size * 2) {
+ //time to do a FFT
+ smbFft(fftw, fft_size * 2, -1);
+ smbFft(fftw + fft_size * 4, fft_size * 2, -1);
+ int next = (fft_pos + 1) % fft_count;
+
+ AudioFrame *hw = (AudioFrame *)fft_history[next].ptr(); //do not use write, avoid cow
+
+ for (int i = 0; i < fft_size; i++) {
+ //abs(vec)/fft_size normalizes each frequency
+ float window = 1.0; //-.5 * Math::cos(2. * Math_PI * (double)i / (double)fft_size) + .5;
+ hw[i].l = window * Vector2(fftw[i * 2], fftw[i * 2 + 1]).length() / float(fft_size);
+ hw[i].r = window * Vector2(fftw[fft_size * 4 + i * 2], fftw[fft_size * 4 + i * 2 + 1]).length() / float(fft_size);
+ }
+
+ fft_pos = next; //swap
+ temporal_fft_pos = 0;
+ }
+ }
+
+ //determine time of capture
+ double remainer_sec = (temporal_fft_pos / mix_rate); //substract remainder from mix time
+ last_fft_time = time - uint64_t(remainer_sec * 1000000.0);
+}
+
+void AudioEffectSpectrumAnalyzerInstance::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("get_magnitude_for_frequency_range", "from_hz", "to_hz", "mode"), &AudioEffectSpectrumAnalyzerInstance::get_magnitude_for_frequency_range, DEFVAL(MAGNITUDE_MAX));
+ BIND_ENUM_CONSTANT(MAGNITUDE_AVERAGE);
+ BIND_ENUM_CONSTANT(MAGNITUDE_MAX);
+}
+
+Vector2 AudioEffectSpectrumAnalyzerInstance::get_magnitude_for_frequency_range(float p_begin, float p_end, MagnitudeMode p_mode) const {
+
+ if (last_fft_time == 0) {
+ return Vector2();
+ }
+ uint64_t time = OS::get_singleton()->get_ticks_usec();
+ float diff = double(time - last_fft_time) / 1000000.0 + base->get_tap_back_pos();
+ diff -= AudioServer::get_singleton()->get_output_latency();
+ float fft_time_size = float(fft_size) / mix_rate;
+
+ int fft_index = fft_pos;
+
+ while (diff > fft_time_size) {
+ diff -= fft_time_size;
+ fft_index -= 1;
+ if (fft_index < 0) {
+ fft_index = fft_count - 1;
+ }
+ }
+
+ int begin_pos = p_begin * fft_size / (mix_rate * 0.5);
+ int end_pos = p_end * fft_size / (mix_rate * 0.5);
+
+ begin_pos = CLAMP(begin_pos, 0, fft_size - 1);
+ end_pos = CLAMP(end_pos, 0, fft_size - 1);
+
+ if (begin_pos > end_pos) {
+ SWAP(begin_pos, end_pos);
+ }
+ const AudioFrame *r = fft_history[fft_index].ptr();
+
+ if (p_mode == MAGNITUDE_AVERAGE) {
+ Vector2 avg;
+
+ for (int i = begin_pos; i <= end_pos; i++) {
+ avg += Vector2(r[i]);
+ }
+
+ avg /= float(end_pos - begin_pos + 1);
+
+ return avg;
+ } else {
+
+ Vector2 max;
+
+ for (int i = begin_pos; i <= end_pos; i++) {
+ max.x = MAX(max.x, r[i].l);
+ max.y = MAX(max.x, r[i].r);
+ }
+
+ return max;
+ }
+}
+
+Ref<AudioEffectInstance> AudioEffectSpectrumAnalyzer::instance() {
+
+ Ref<AudioEffectSpectrumAnalyzerInstance> ins;
+ ins.instance();
+ ins->base = Ref<AudioEffectSpectrumAnalyzer>(this);
+ static const int fft_sizes[FFT_SIZE_MAX] = { 256, 512, 1024, 2048, 4096 };
+ ins->fft_size = fft_sizes[fft_size];
+ ins->mix_rate = AudioServer::get_singleton()->get_mix_rate();
+ ins->fft_count = (buffer_length / (float(ins->fft_size) / ins->mix_rate)) + 1;
+ ins->fft_pos = 0;
+ ins->last_fft_time = 0;
+ ins->fft_history.resize(ins->fft_count);
+ ins->temporal_fft.resize(ins->fft_size * 8); //x2 stereo, x2 amount of samples for freqs, x2 for input
+ ins->temporal_fft_pos = 0;
+ for (int i = 0; i < ins->fft_count; i++) {
+ ins->fft_history.write[i].resize(ins->fft_size); //only magnitude matters
+ for (int j = 0; j < ins->fft_size; j++) {
+ ins->fft_history.write[i].write[j] = AudioFrame(0, 0);
+ }
+ }
+ return ins;
+}
+
+void AudioEffectSpectrumAnalyzer::set_buffer_length(float p_volume) {
+ buffer_length = p_volume;
+}
+
+float AudioEffectSpectrumAnalyzer::get_buffer_length() const {
+
+ return buffer_length;
+}
+
+void AudioEffectSpectrumAnalyzer::set_tap_back_pos(float p_seconds) {
+ tapback_pos = p_seconds;
+}
+
+float AudioEffectSpectrumAnalyzer::get_tap_back_pos() const {
+ return tapback_pos;
+}
+
+void AudioEffectSpectrumAnalyzer::set_fft_size(FFT_Size p_fft_size) {
+ ERR_FAIL_INDEX(p_fft_size, FFT_SIZE_MAX);
+ fft_size = p_fft_size;
+}
+
+AudioEffectSpectrumAnalyzer::FFT_Size AudioEffectSpectrumAnalyzer::get_fft_size() const {
+ return fft_size;
+}
+
+void AudioEffectSpectrumAnalyzer::_bind_methods() {
+
+ ClassDB::bind_method(D_METHOD("set_buffer_length", "seconds"), &AudioEffectSpectrumAnalyzer::set_buffer_length);
+ ClassDB::bind_method(D_METHOD("get_buffer_length"), &AudioEffectSpectrumAnalyzer::get_buffer_length);
+
+ ClassDB::bind_method(D_METHOD("set_tap_back_pos", "seconds"), &AudioEffectSpectrumAnalyzer::set_tap_back_pos);
+ ClassDB::bind_method(D_METHOD("get_tap_back_pos"), &AudioEffectSpectrumAnalyzer::get_tap_back_pos);
+
+ ClassDB::bind_method(D_METHOD("set_fft_size", "size"), &AudioEffectSpectrumAnalyzer::set_fft_size);
+ ClassDB::bind_method(D_METHOD("get_fft_size"), &AudioEffectSpectrumAnalyzer::get_fft_size);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "buffer_length", PROPERTY_HINT_RANGE, "0.1,4,0.1"), "set_buffer_length", "get_buffer_length");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "tap_back_pos", PROPERTY_HINT_RANGE, "0.1,4,0.1"), "set_tap_back_pos", "get_tap_back_pos");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "fft_size", PROPERTY_HINT_ENUM, "256,512,1024,2048,4096"), "set_fft_size", "get_fft_size");
+
+ BIND_ENUM_CONSTANT(FFT_SIZE_256);
+ BIND_ENUM_CONSTANT(FFT_SIZE_512);
+ BIND_ENUM_CONSTANT(FFT_SIZE_1024);
+ BIND_ENUM_CONSTANT(FFT_SIZE_2048);
+ BIND_ENUM_CONSTANT(FFT_SIZE_4096);
+ BIND_ENUM_CONSTANT(FFT_SIZE_MAX);
+}
+
+AudioEffectSpectrumAnalyzer::AudioEffectSpectrumAnalyzer() {
+ buffer_length = 2;
+ tapback_pos = 0.01;
+ fft_size = FFT_SIZE_1024;
+}
diff --git a/servers/audio/effects/audio_effect_spectrum_analyzer.h b/servers/audio/effects/audio_effect_spectrum_analyzer.h
new file mode 100644
index 0000000000..0534426da3
--- /dev/null
+++ b/servers/audio/effects/audio_effect_spectrum_analyzer.h
@@ -0,0 +1,76 @@
+#ifndef AUDIO_EFFECT_SPECTRUM_ANALYZER_H
+#define AUDIO_EFFECT_SPECTRUM_ANALYZER_H
+
+#include "servers/audio/audio_effect.h"
+
+class AudioEffectSpectrumAnalyzer;
+
+class AudioEffectSpectrumAnalyzerInstance : public AudioEffectInstance {
+ GDCLASS(AudioEffectSpectrumAnalyzerInstance, AudioEffectInstance)
+
+public:
+ enum MagnitudeMode {
+ MAGNITUDE_AVERAGE,
+ MAGNITUDE_MAX,
+ };
+
+private:
+ friend class AudioEffectSpectrumAnalyzer;
+ Ref<AudioEffectSpectrumAnalyzer> base;
+
+ Vector<Vector<AudioFrame> > fft_history;
+ Vector<float> temporal_fft;
+ int temporal_fft_pos;
+ int fft_size;
+ int fft_count;
+ int fft_pos;
+ float mix_rate;
+ uint64_t last_fft_time;
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count);
+ Vector2 get_magnitude_for_frequency_range(float p_begin, float p_end, MagnitudeMode p_mode = MAGNITUDE_MAX) const;
+};
+
+VARIANT_ENUM_CAST(AudioEffectSpectrumAnalyzerInstance::MagnitudeMode)
+
+class AudioEffectSpectrumAnalyzer : public AudioEffect {
+ GDCLASS(AudioEffectSpectrumAnalyzer, AudioEffect)
+public:
+ enum FFT_Size {
+ FFT_SIZE_256,
+ FFT_SIZE_512,
+ FFT_SIZE_1024,
+ FFT_SIZE_2048,
+ FFT_SIZE_4096,
+ FFT_SIZE_MAX
+ };
+
+public:
+ friend class AudioEffectSpectrumAnalyzerInstance;
+ float buffer_length;
+ float tapback_pos;
+ FFT_Size fft_size;
+
+protected:
+ static void _bind_methods();
+
+public:
+ Ref<AudioEffectInstance> instance();
+ void set_buffer_length(float p_seconds);
+ float get_buffer_length() const;
+ void set_tap_back_pos(float p_seconds);
+ float get_tap_back_pos() const;
+
+ void set_fft_size(FFT_Size);
+ FFT_Size get_fft_size() const;
+
+ AudioEffectSpectrumAnalyzer();
+};
+
+VARIANT_ENUM_CAST(AudioEffectSpectrumAnalyzer::FFT_Size);
+
+#endif // AUDIO_EFFECT_SPECTRUM_ANALYZER_H
diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp
new file mode 100644
index 0000000000..f4a66b5643
--- /dev/null
+++ b/servers/audio/effects/audio_stream_generator.cpp
@@ -0,0 +1,182 @@
+#include "audio_stream_generator.h"
+
+void AudioStreamGenerator::set_mix_rate(float p_mix_rate) {
+ mix_rate = p_mix_rate;
+}
+
+float AudioStreamGenerator::get_mix_rate() const {
+
+ return mix_rate;
+}
+
+void AudioStreamGenerator::set_buffer_length(float p_seconds) {
+
+ buffer_len = p_seconds;
+}
+float AudioStreamGenerator::get_buffer_length() const {
+
+ return buffer_len;
+}
+
+Ref<AudioStreamPlayback> AudioStreamGenerator::instance_playback() {
+
+ Ref<AudioStreamGeneratorPlayback> playback;
+ playback.instance();
+ playback->generator = this;
+ int target_buffer_size = mix_rate * buffer_len;
+ playback->buffer.resize(nearest_shift(target_buffer_size));
+ playback->buffer.clear();
+ return playback;
+}
+String AudioStreamGenerator::get_stream_name() const {
+
+ return "UserFeed";
+}
+
+float AudioStreamGenerator::get_length() const {
+ return 0;
+}
+
+void AudioStreamGenerator::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("set_mix_rate", "hz"), &AudioStreamGenerator::set_mix_rate);
+ ClassDB::bind_method(D_METHOD("get_mix_rate"), &AudioStreamGenerator::get_mix_rate);
+
+ ClassDB::bind_method(D_METHOD("set_buffer_length", "seconds"), &AudioStreamGenerator::set_buffer_length);
+ ClassDB::bind_method(D_METHOD("get_buffer_length"), &AudioStreamGenerator::get_buffer_length);
+
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "mix_rate", PROPERTY_HINT_RANGE, "20,192000,1"), "set_mix_rate", "get_mix_rate");
+ ADD_PROPERTY(PropertyInfo(Variant::REAL, "buffer_length", PROPERTY_HINT_RANGE, "0.01,10,0.01"), "set_buffer_length", "get_buffer_length");
+}
+
+AudioStreamGenerator::AudioStreamGenerator() {
+ mix_rate = 44100;
+ buffer_len = 0.5;
+}
+
+////////////////
+
+bool AudioStreamGeneratorPlayback::push_frame(const Vector2 &p_frame) {
+ if (buffer.space_left() < 1) {
+ return false;
+ }
+
+ AudioFrame f = p_frame;
+
+ buffer.write(&f, 1);
+ return true;
+}
+
+bool AudioStreamGeneratorPlayback::can_push_buffer(int p_frames) const {
+ return buffer.space_left() >= p_frames;
+}
+bool AudioStreamGeneratorPlayback::push_buffer(const PoolVector2Array &p_frames) {
+
+ int to_write = p_frames.size();
+ if (buffer.space_left() < to_write) {
+ return false;
+ }
+
+ PoolVector2Array::Read r = p_frames.read();
+ if (sizeof(real_t) == 4) {
+ //write directly
+ buffer.write((const AudioFrame *)r.ptr(), to_write);
+ } else {
+ //convert from double
+ AudioFrame buf[2048];
+ int ofs = 0;
+ while (to_write) {
+
+ int w = MIN(to_write, 2048);
+ for (int i = 0; i < w; i++) {
+ buf[i] = r[i + ofs];
+ }
+ buffer.write(buf, w);
+ ofs += w;
+ to_write -= w;
+ }
+ }
+ return true;
+}
+
+int AudioStreamGeneratorPlayback::get_frames_available() const {
+ return buffer.space_left();
+}
+
+int AudioStreamGeneratorPlayback::get_skips() const {
+ return skips;
+}
+
+void AudioStreamGeneratorPlayback::clear_buffer() {
+ ERR_FAIL_COND(active);
+ buffer.clear();
+ mixed = 0;
+}
+
+void AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+
+ int read_amount = buffer.data_left();
+ if (p_frames < read_amount) {
+ read_amount = p_frames;
+ }
+
+ buffer.read(p_buffer, read_amount);
+
+ if (read_amount < p_frames) {
+ //skipped, not ideal
+ for (int i = read_amount; i < p_frames; i++) {
+ p_buffer[i] = AudioFrame(0, 0);
+ }
+
+ skips++;
+ }
+
+ mixed += p_frames / generator->get_mix_rate();
+}
+float AudioStreamGeneratorPlayback::get_stream_sampling_rate() {
+ return generator->get_mix_rate();
+}
+
+void AudioStreamGeneratorPlayback::start(float p_from_pos) {
+
+ if (mixed == 0.0) {
+ _begin_resample();
+ }
+ skips = 0;
+ active = true;
+ mixed = 0.0;
+}
+
+void AudioStreamGeneratorPlayback::stop() {
+ active = false;
+}
+bool AudioStreamGeneratorPlayback::is_playing() const {
+
+ return active; //always playing, can't be stopped
+}
+
+int AudioStreamGeneratorPlayback::get_loop_count() const {
+ return 0;
+}
+
+float AudioStreamGeneratorPlayback::get_playback_position() const {
+ return mixed;
+}
+void AudioStreamGeneratorPlayback::seek(float p_time) {
+ //no seek possible
+}
+
+void AudioStreamGeneratorPlayback::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("push_frame", "frame"), &AudioStreamGeneratorPlayback::push_frame);
+ ClassDB::bind_method(D_METHOD("can_push_buffer", "amount"), &AudioStreamGeneratorPlayback::can_push_buffer);
+ ClassDB::bind_method(D_METHOD("push_buffer", "frames"), &AudioStreamGeneratorPlayback::push_buffer);
+ ClassDB::bind_method(D_METHOD("get_frames_available"), &AudioStreamGeneratorPlayback::get_frames_available);
+ ClassDB::bind_method(D_METHOD("get_skips"), &AudioStreamGeneratorPlayback::get_skips);
+ ClassDB::bind_method(D_METHOD("clear_buffer"), &AudioStreamGeneratorPlayback::clear_buffer);
+}
+
+AudioStreamGeneratorPlayback::AudioStreamGeneratorPlayback() {
+ generator = NULL;
+ skips = 0;
+ active = false;
+ mixed = 0;
+}
diff --git a/servers/audio/effects/audio_stream_generator.h b/servers/audio/effects/audio_stream_generator.h
new file mode 100644
index 0000000000..2082682907
--- /dev/null
+++ b/servers/audio/effects/audio_stream_generator.h
@@ -0,0 +1,66 @@
+#ifndef AUDIO_STREAM_USER_FED_H
+#define AUDIO_STREAM_USER_FED_H
+
+#include "core/ring_buffer.h"
+#include "servers/audio/audio_stream.h"
+
+class AudioStreamGenerator : public AudioStream {
+ GDCLASS(AudioStreamGenerator, AudioStream)
+
+ float mix_rate;
+ float buffer_len;
+
+protected:
+ static void _bind_methods();
+
+public:
+ void set_mix_rate(float p_mix_rate);
+ float get_mix_rate() const;
+
+ void set_buffer_length(float p_seconds);
+ float get_buffer_length() const;
+
+ virtual Ref<AudioStreamPlayback> instance_playback();
+ virtual String get_stream_name() const;
+
+ virtual float get_length() const;
+ AudioStreamGenerator();
+};
+
+class AudioStreamGeneratorPlayback : public AudioStreamPlaybackResampled {
+
+ GDCLASS(AudioStreamGeneratorPlayback, AudioStreamPlaybackResampled)
+ friend class AudioStreamGenerator;
+ RingBuffer<AudioFrame> buffer;
+ int skips;
+ bool active;
+ float mixed;
+ AudioStreamGenerator *generator;
+
+protected:
+ virtual void _mix_internal(AudioFrame *p_buffer, int p_frames);
+ virtual float get_stream_sampling_rate();
+
+ static void _bind_methods();
+
+public:
+ virtual void start(float p_from_pos = 0.0);
+ virtual void stop();
+ virtual bool is_playing() const;
+
+ virtual int get_loop_count() const; //times it looped
+
+ virtual float get_playback_position() const;
+ virtual void seek(float p_time);
+
+ bool push_frame(const Vector2 &p_frame);
+ bool can_push_buffer(int p_frames) const;
+ bool push_buffer(const PoolVector2Array &p_frames);
+ int get_frames_available() const;
+ int get_skips() const;
+
+ void clear_buffer();
+
+ AudioStreamGeneratorPlayback();
+};
+#endif // AUDIO_STREAM_USER_FED_H
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 8c092a02a2..fc3ecedd03 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -68,16 +68,21 @@ void AudioDriver::audio_server_process(int p_frames, int32_t *p_buffer, bool p_u
void AudioDriver::update_mix_time(int p_frames) {
- _mix_amount += p_frames;
+ _last_mix_frames = p_frames;
if (OS::get_singleton())
_last_mix_time = OS::get_singleton()->get_ticks_usec();
}
-double AudioDriver::get_mix_time() const {
+double AudioDriver::get_time_since_last_mix() const {
+
+ return (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0;
+}
+
+double AudioDriver::get_time_to_next_mix() const {
double total = (OS::get_singleton()->get_ticks_usec() - _last_mix_time) / 1000000.0;
- total += _mix_amount / (double)get_mix_rate();
- return total;
+ double mix_buffer = _last_mix_frames / (double)get_mix_rate();
+ return mix_buffer - total;
}
void AudioDriver::input_buffer_init(int driver_buffer_frames) {
@@ -148,7 +153,7 @@ Array AudioDriver::capture_get_device_list() {
AudioDriver::AudioDriver() {
_last_mix_time = 0;
- _mix_amount = 0;
+ _last_mix_frames = 0;
input_position = 0;
input_size = 0;
@@ -281,13 +286,6 @@ void AudioServer::_driver_process(int p_frames, int32_t *p_buffer) {
to_mix -= to_copy;
}
- // Calculate latency for Performance.AUDIO_OUTPUT_LATENCY
- if (OS::get_singleton()) {
- uint64_t ticks = OS::get_singleton()->get_ticks_usec();
- output_latency = (ticks - output_latency_ticks) / 1000000.f;
- output_latency_ticks = ticks;
- }
-
#ifdef DEBUG_ENABLED
prof_time += OS::get_singleton()->get_ticks_usec() - prof_ticks;
#endif
@@ -876,6 +874,15 @@ int AudioServer::get_bus_effect_count(int p_bus) {
return buses[p_bus]->effects.size();
}
+Ref<AudioEffectInstance> AudioServer::get_bus_effect_instance(int p_bus, int p_effect, int p_channel) {
+
+ ERR_FAIL_INDEX_V(p_bus, buses.size(), Ref<AudioEffectInstance>());
+ ERR_FAIL_INDEX_V(p_effect, buses[p_bus]->effects.size(), Ref<AudioEffectInstance>());
+ ERR_FAIL_INDEX_V(p_channel, buses[p_bus]->channels.size(), Ref<AudioEffectInstance>());
+
+ return buses[p_bus]->channels[p_channel].effect_instances[p_effect];
+}
+
Ref<AudioEffect> AudioServer::get_bus_effect(int p_bus, int p_effect) {
ERR_FAIL_INDEX_V(p_bus, buses.size(), Ref<AudioEffect>());
@@ -1045,8 +1052,10 @@ void AudioServer::update() {
void AudioServer::load_default_bus_layout() {
- if (ResourceLoader::exists("res://default_bus_layout.tres")) {
- Ref<AudioBusLayout> default_layout = ResourceLoader::load("res://default_bus_layout.tres");
+ String layout_path = ProjectSettings::get_singleton()->get("audio/default_bus_layout");
+
+ if (ResourceLoader::exists(layout_path)) {
+ Ref<AudioBusLayout> default_layout = ResourceLoader::load(layout_path);
if (default_layout.is_valid()) {
set_bus_layout(default_layout);
}
@@ -1096,13 +1105,19 @@ AudioServer *AudioServer::get_singleton() {
return singleton;
}
-double AudioServer::get_mix_time() const {
+double AudioServer::get_output_latency() const {
- return 0;
+ return AudioDriver::get_singleton()->get_latency();
}
-double AudioServer::get_output_delay() const {
- return 0;
+double AudioServer::get_time_to_next_mix() const {
+
+ return AudioDriver::get_singleton()->get_time_to_next_mix();
+}
+
+double AudioServer::get_time_since_last_mix() const {
+
+ return AudioDriver::get_singleton()->get_time_since_last_mix();
}
AudioServer *AudioServer::singleton = NULL;
@@ -1328,6 +1343,7 @@ void AudioServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bus_effect_count", "bus_idx"), &AudioServer::get_bus_effect_count);
ClassDB::bind_method(D_METHOD("get_bus_effect", "bus_idx", "effect_idx"), &AudioServer::get_bus_effect);
+ ClassDB::bind_method(D_METHOD("get_bus_effect_instance", "bus_idx", "effect_idx", "channel"), &AudioServer::get_bus_effect_instance, DEFVAL(0));
ClassDB::bind_method(D_METHOD("swap_bus_effects", "bus_idx", "effect_idx", "by_effect_idx"), &AudioServer::swap_bus_effects);
ClassDB::bind_method(D_METHOD("set_bus_effect_enabled", "bus_idx", "effect_idx", "enabled"), &AudioServer::set_bus_effect_enabled);
@@ -1345,6 +1361,10 @@ void AudioServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_device"), &AudioServer::get_device);
ClassDB::bind_method(D_METHOD("set_device", "device"), &AudioServer::set_device);
+ ClassDB::bind_method(D_METHOD("get_time_to_next_mix"), &AudioServer::get_time_to_next_mix);
+ ClassDB::bind_method(D_METHOD("get_time_since_last_mix"), &AudioServer::get_time_since_last_mix);
+ ClassDB::bind_method(D_METHOD("get_output_latency"), &AudioServer::get_output_latency);
+
ClassDB::bind_method(D_METHOD("capture_get_device_list"), &AudioServer::capture_get_device_list);
ClassDB::bind_method(D_METHOD("capture_get_device"), &AudioServer::capture_get_device);
ClassDB::bind_method(D_METHOD("capture_set_device", "name"), &AudioServer::capture_set_device);
@@ -1374,6 +1394,8 @@ AudioServer::AudioServer() {
#ifdef DEBUG_ENABLED
prof_time = 0;
#endif
+ mix_time = 0;
+ mix_size = 0;
}
AudioServer::~AudioServer() {
diff --git a/servers/audio_server.h b/servers/audio_server.h
index 6bd8093c76..e56d87ce84 100644
--- a/servers/audio_server.h
+++ b/servers/audio_server.h
@@ -45,7 +45,7 @@ class AudioDriver {
static AudioDriver *singleton;
uint64_t _last_mix_time;
- uint64_t _mix_amount;
+ uint64_t _last_mix_frames;
#ifdef DEBUG_ENABLED
uint64_t prof_ticks;
@@ -71,7 +71,8 @@ protected:
#endif
public:
- double get_mix_time() const; //useful for video -> audio sync
+ double get_time_since_last_mix() const; //useful for video -> audio sync
+ double get_time_to_next_mix() const;
enum SpeakerMode {
SPEAKER_MODE_STEREO,
@@ -163,6 +164,9 @@ public:
typedef void (*AudioCallback)(void *p_userdata);
private:
+ uint64_t mix_time;
+ int mix_size;
+
uint32_t buffer_size;
uint64_t mix_count;
uint64_t mix_frames;
@@ -322,6 +326,7 @@ public:
int get_bus_effect_count(int p_bus);
Ref<AudioEffect> get_bus_effect(int p_bus, int p_effect);
+ Ref<AudioEffectInstance> get_bus_effect_instance(int p_bus, int p_effect, int p_channel = 0);
void swap_bus_effects(int p_bus, int p_effect, int p_by_effect);
@@ -350,8 +355,9 @@ public:
static AudioServer *get_singleton();
- virtual double get_mix_time() const; //useful for video -> audio sync
- virtual double get_output_delay() const;
+ virtual double get_output_latency() const;
+ virtual double get_time_to_next_mix() const;
+ virtual double get_time_since_last_mix() const;
void *audio_data_alloc(uint32_t p_data_len, const uint8_t *p_from_data = NULL);
void audio_data_free(void *p_data);
@@ -376,7 +382,6 @@ public:
String capture_get_device();
void capture_set_device(const String &p_name);
- float get_output_latency() { return output_latency; }
AudioServer();
virtual ~AudioServer();
};
diff --git a/servers/physics/body_sw.cpp b/servers/physics/body_sw.cpp
index f0fbbafe1c..b4c3670a7b 100644
--- a/servers/physics/body_sw.cpp
+++ b/servers/physics/body_sw.cpp
@@ -196,7 +196,8 @@ void BodySW::set_param(PhysicsServer::BodyParameter p_param, real_t p_value) {
angular_damp = p_value;
} break;
- default: {}
+ default: {
+ }
}
}
@@ -226,7 +227,8 @@ real_t BodySW::get_param(PhysicsServer::BodyParameter p_param) const {
return angular_damp;
} break;
- default: {}
+ default: {
+ }
}
return 0;
@@ -474,7 +476,8 @@ void BodySW::integrate_forces(real_t p_step) {
_compute_area_gravity_and_dampenings(aa[i].area);
stopped = mode == PhysicsServer::AREA_SPACE_OVERRIDE_REPLACE;
} break;
- default: {}
+ default: {
+ }
}
}
}
diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp
index 085ad4f9ea..b1c21290ab 100644
--- a/servers/physics/collision_object_sw.cpp
+++ b/servers/physics/collision_object_sw.cpp
@@ -32,13 +32,14 @@
#include "servers/physics/physics_server_sw.h"
#include "space_sw.h"
-void CollisionObjectSW::add_shape(ShapeSW *p_shape, const Transform &p_transform) {
+void CollisionObjectSW::add_shape(ShapeSW *p_shape, const Transform &p_transform, bool p_disabled) {
Shape s;
s.shape = p_shape;
s.xform = p_transform;
s.xform_inv = s.xform.affine_inverse();
s.bpid = 0; //needs update
+ s.disabled = p_disabled;
shapes.push_back(s);
p_shape->add_owner(this);
diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h
index 5c14d5aaf9..c2c3fe0e5a 100644
--- a/servers/physics/collision_object_sw.h
+++ b/servers/physics/collision_object_sw.h
@@ -118,7 +118,7 @@ public:
void _shape_changed();
_FORCE_INLINE_ Type get_type() const { return type; }
- void add_shape(ShapeSW *p_shape, const Transform &p_transform = Transform());
+ void add_shape(ShapeSW *p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
void set_shape(int p_index, ShapeSW *p_shape);
void set_shape_transform(int p_index, const Transform &p_transform);
_FORCE_INLINE_ int get_shape_count() const { return shapes.size(); }
diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp
index baf7431e28..3073cc8b11 100644
--- a/servers/physics/collision_solver_sat.cpp
+++ b/servers/physics/collision_solver_sat.cpp
@@ -98,7 +98,7 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
Vector3 c = rel_A.cross(rel_B).cross(rel_B);
- if (Math::abs(rel_A.dot(c)) < CMP_EPSILON) {
+ if (Math::is_zero_approx(rel_A.dot(c))) {
// should handle somehow..
//ERR_PRINT("TODO FIX");
@@ -678,7 +678,7 @@ static void _collision_box_box(const ShapeSW *p_a, const Transform &p_transform_
Vector3 axis = p_transform_a.basis.get_axis(i).cross(p_transform_b.basis.get_axis(j));
- if (axis.length_squared() < CMP_EPSILON)
+ if (Math::is_zero_approx(axis.length_squared()))
continue;
axis.normalize();
@@ -767,7 +767,7 @@ static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transf
// cylinder
Vector3 box_axis = p_transform_a.basis.get_axis(i);
Vector3 axis = box_axis.cross(cyl_axis);
- if (axis.length_squared() < CMP_EPSILON)
+ if (Math::is_zero_approx(axis.length_squared()))
continue;
if (!separator.test_axis(axis.normalized()))
diff --git a/servers/physics/joints/cone_twist_joint_sw.cpp b/servers/physics/joints/cone_twist_joint_sw.cpp
index 268b9eefeb..1b3de3e913 100644
--- a/servers/physics/joints/cone_twist_joint_sw.cpp
+++ b/servers/physics/joints/cone_twist_joint_sw.cpp
@@ -127,10 +127,10 @@ bool ConeTwistJointSW::setup(real_t p_timestep) {
Vector3 relPos = pivotBInW - pivotAInW;
Vector3 normal[3];
- if (relPos.length_squared() > CMP_EPSILON) {
- normal[0] = relPos.normalized();
- } else {
+ if (Math::is_zero_approx(relPos.length_squared())) {
normal[0] = Vector3(real_t(1.0), 0, 0);
+ } else {
+ normal[0] = relPos.normalized();
}
plane_space(normal[0], normal[1], normal[2]);
diff --git a/servers/physics/joints/generic_6dof_joint_sw.cpp b/servers/physics/joints/generic_6dof_joint_sw.cpp
index 756348f448..813d9b7704 100644
--- a/servers/physics/joints/generic_6dof_joint_sw.cpp
+++ b/servers/physics/joints/generic_6dof_joint_sw.cpp
@@ -107,7 +107,7 @@ real_t G6DOFRotationalLimitMotorSW::solveAngularLimits(
// correction velocity
real_t motor_relvel = m_limitSoftness * (target_velocity - m_damping * rel_vel);
- if (motor_relvel < CMP_EPSILON && motor_relvel > -CMP_EPSILON) {
+ if (Math::is_zero_approx(motor_relvel)) {
return 0.0f; //no need for applying force
}
diff --git a/servers/physics/joints/hinge_joint_sw.cpp b/servers/physics/joints/hinge_joint_sw.cpp
index e972496b2b..1d1b30286e 100644
--- a/servers/physics/joints/hinge_joint_sw.cpp
+++ b/servers/physics/joints/hinge_joint_sw.cpp
@@ -167,10 +167,10 @@ bool HingeJointSW::setup(real_t p_step) {
Vector3 relPos = pivotBInW - pivotAInW;
Vector3 normal[3];
- if (relPos.length_squared() > CMP_EPSILON) {
- normal[0] = relPos.normalized();
- } else {
+ if (Math::is_zero_approx(relPos.length_squared())) {
normal[0] = Vector3(real_t(1.0), 0, 0);
+ } else {
+ normal[0] = relPos.normalized();
}
plane_space(normal[0], normal[1], normal[2]);
diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp
index 36d18e8901..66170f5a2e 100644
--- a/servers/physics/physics_server_sw.cpp
+++ b/servers/physics/physics_server_sw.cpp
@@ -283,7 +283,7 @@ PhysicsServer::AreaSpaceOverrideMode PhysicsServerSW::area_get_space_override_mo
return area->get_space_override_mode();
}
-void PhysicsServerSW::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform) {
+void PhysicsServerSW::area_add_shape(RID p_area, RID p_shape, const Transform &p_transform, bool p_disabled) {
AreaSW *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
@@ -291,7 +291,7 @@ void PhysicsServerSW::area_add_shape(RID p_area, RID p_shape, const Transform &p
ShapeSW *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- area->add_shape(shape, p_transform);
+ area->add_shape(shape, p_transform, p_disabled);
}
void PhysicsServerSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
@@ -540,7 +540,7 @@ PhysicsServer::BodyMode PhysicsServerSW::body_get_mode(RID p_body) const {
return body->get_mode();
};
-void PhysicsServerSW::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform) {
+void PhysicsServerSW::body_add_shape(RID p_body, RID p_shape, const Transform &p_transform, bool p_disabled) {
BodySW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
@@ -548,7 +548,7 @@ void PhysicsServerSW::body_add_shape(RID p_body, RID p_shape, const Transform &p
ShapeSW *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- body->add_shape(shape, p_transform);
+ body->add_shape(shape, p_transform, p_disabled);
}
void PhysicsServerSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h
index 5d0ba3628e..dc1cbca94d 100644
--- a/servers/physics/physics_server_sw.h
+++ b/servers/physics/physics_server_sw.h
@@ -119,7 +119,7 @@ public:
virtual void area_set_space(RID p_area, RID p_space);
virtual RID area_get_space(RID p_area) const;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform());
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform);
@@ -163,7 +163,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode);
virtual BodyMode body_get_mode(RID p_body) const;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform());
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false);
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform);
diff --git a/servers/physics/space_sw.cpp b/servers/physics/space_sw.cpp
index 9920391471..8b9f210850 100644
--- a/servers/physics/space_sw.cpp
+++ b/servers/physics/space_sw.cpp
@@ -351,10 +351,8 @@ bool PhysicsDirectSpaceStateSW::collide_shape(RID p_shape, const Transform &p_sh
CollisionSolverSW::CallbackResult cbkres = NULL;
PhysicsServerSW::CollCbkData *cbkptr = NULL;
- if (p_result_max > 0) {
- cbkptr = &cbk;
- cbkres = PhysicsServerSW::_shape_col_cbk;
- }
+ cbkptr = &cbk;
+ cbkres = PhysicsServerSW::_shape_col_cbk;
for (int i = 0; i < amount; i++) {
diff --git a/servers/physics_2d/body_2d_sw.cpp b/servers/physics_2d/body_2d_sw.cpp
index 60bcb2e28e..60bbcef4b6 100644
--- a/servers/physics_2d/body_2d_sw.cpp
+++ b/servers/physics_2d/body_2d_sw.cpp
@@ -174,7 +174,8 @@ void Body2DSW::set_param(Physics2DServer::BodyParameter p_param, real_t p_value)
angular_damp = p_value;
} break;
- default: {}
+ default: {
+ }
}
}
@@ -206,7 +207,8 @@ real_t Body2DSW::get_param(Physics2DServer::BodyParameter p_param) const {
return angular_damp;
} break;
- default: {}
+ default: {
+ }
}
return 0;
@@ -443,7 +445,8 @@ void Body2DSW::integrate_forces(real_t p_step) {
_compute_area_gravity_and_dampenings(aa[i].area);
stopped = mode == Physics2DServer::AREA_SPACE_OVERRIDE_REPLACE;
} break;
- default: {}
+ default: {
+ }
}
}
}
diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp
index 4ec92497e7..445a2e0613 100644
--- a/servers/physics_2d/collision_object_2d_sw.cpp
+++ b/servers/physics_2d/collision_object_2d_sw.cpp
@@ -31,14 +31,14 @@
#include "collision_object_2d_sw.h"
#include "space_2d_sw.h"
-void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_transform) {
+void CollisionObject2DSW::add_shape(Shape2DSW *p_shape, const Transform2D &p_transform, bool p_disabled) {
Shape s;
s.shape = p_shape;
s.xform = p_transform;
s.xform_inv = s.xform.affine_inverse();
s.bpid = 0; //needs update
- s.disabled = false;
+ s.disabled = p_disabled;
s.one_way_collision = false;
s.one_way_collision_margin = 0;
shapes.push_back(s);
diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h
index d5e815ff45..fa18e61262 100644
--- a/servers/physics_2d/collision_object_2d_sw.h
+++ b/servers/physics_2d/collision_object_2d_sw.h
@@ -111,7 +111,7 @@ public:
void _shape_changed();
_FORCE_INLINE_ Type get_type() const { return type; }
- void add_shape(Shape2DSW *p_shape, const Transform2D &p_transform = Transform2D());
+ void add_shape(Shape2DSW *p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
void set_shape(int p_index, Shape2DSW *p_shape);
void set_shape_transform(int p_index, const Transform2D &p_transform);
void set_shape_metadata(int p_index, const Variant &p_metadata);
diff --git a/servers/physics_2d/collision_solver_2d_sat.cpp b/servers/physics_2d/collision_solver_2d_sat.cpp
index d6c3fff421..f4bff66389 100644
--- a/servers/physics_2d/collision_solver_2d_sat.cpp
+++ b/servers/physics_2d/collision_solver_2d_sat.cpp
@@ -237,8 +237,8 @@ public:
Vector2 axis = p_axis;
- if (Math::abs(axis.x) < CMP_EPSILON &&
- Math::abs(axis.y) < CMP_EPSILON) {
+ if (Math::is_zero_approx(axis.x) &&
+ Math::is_zero_approx(axis.y)) {
// strange case, try an upwards separator
axis = Vector2(0.0, 1.0);
}
diff --git a/servers/physics_2d/joints_2d_sw.cpp b/servers/physics_2d/joints_2d_sw.cpp
index 5c2242c4c5..954b0fa3ea 100644
--- a/servers/physics_2d/joints_2d_sw.cpp
+++ b/servers/physics_2d/joints_2d_sw.cpp
@@ -299,9 +299,7 @@ bool GrooveJoint2DSW::setup(real_t p_step) {
Vector2 delta = (B->get_transform().get_origin() + rB) - (A->get_transform().get_origin() + rA);
- // FIXME: We used to do this assignment and then override it with 0.001 right after. Investigate why.
- //real_t _b = get_bias();
- real_t _b = 0.001;
+ real_t _b = get_bias();
gbias = (delta * -(_b == 0 ? space->get_constraint_bias() : _b) * (1.0 / p_step)).clamped(get_max_bias());
// apply accumulated impulse
diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp
index 283d20876d..1d02227052 100644
--- a/servers/physics_2d/physics_2d_server_sw.cpp
+++ b/servers/physics_2d/physics_2d_server_sw.cpp
@@ -378,7 +378,7 @@ Physics2DServer::AreaSpaceOverrideMode Physics2DServerSW::area_get_space_overrid
return area->get_space_override_mode();
}
-void Physics2DServerSW::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform) {
+void Physics2DServerSW::area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
Area2DSW *area = area_owner.get(p_area);
ERR_FAIL_COND(!area);
@@ -386,7 +386,7 @@ void Physics2DServerSW::area_add_shape(RID p_area, RID p_shape, const Transform2
Shape2DSW *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- area->add_shape(shape, p_transform);
+ area->add_shape(shape, p_transform, p_disabled);
}
void Physics2DServerSW::area_set_shape(RID p_area, int p_shape_idx, RID p_shape) {
@@ -643,7 +643,7 @@ Physics2DServer::BodyMode Physics2DServerSW::body_get_mode(RID p_body) const {
return body->get_mode();
};
-void Physics2DServerSW::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform) {
+void Physics2DServerSW::body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform, bool p_disabled) {
Body2DSW *body = body_owner.get(p_body);
ERR_FAIL_COND(!body);
@@ -651,7 +651,7 @@ void Physics2DServerSW::body_add_shape(RID p_body, RID p_shape, const Transform2
Shape2DSW *shape = shape_owner.get(p_shape);
ERR_FAIL_COND(!shape);
- body->add_shape(shape, p_transform);
+ body->add_shape(shape, p_transform, p_disabled);
}
void Physics2DServerSW::body_set_shape(RID p_body, int p_shape_idx, RID p_shape) {
diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h
index 4beec41442..6fda74b877 100644
--- a/servers/physics_2d/physics_2d_server_sw.h
+++ b/servers/physics_2d/physics_2d_server_sw.h
@@ -131,7 +131,7 @@ public:
virtual void area_set_space(RID p_area, RID p_space);
virtual RID area_get_space(RID p_area) const;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D());
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape);
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform);
@@ -175,7 +175,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode);
virtual BodyMode body_get_mode(RID p_body) const;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D());
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false);
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape);
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform);
virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata);
diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h
index 5b9a102a1b..b61e1faad2 100644
--- a/servers/physics_2d/physics_2d_server_wrap_mt.h
+++ b/servers/physics_2d/physics_2d_server_wrap_mt.h
@@ -140,7 +140,7 @@ public:
FUNC2(area_set_space_override_mode, RID, AreaSpaceOverrideMode);
FUNC1RC(AreaSpaceOverrideMode, area_get_space_override_mode, RID);
- FUNC3(area_add_shape, RID, RID, const Transform2D &);
+ FUNC4(area_add_shape, RID, RID, const Transform2D &, bool);
FUNC3(area_set_shape, RID, int, RID);
FUNC3(area_set_shape_transform, RID, int, const Transform2D &);
FUNC3(area_set_shape_disabled, RID, int, bool);
@@ -183,7 +183,7 @@ public:
FUNC2(body_set_mode, RID, BodyMode);
FUNC1RC(BodyMode, body_get_mode, RID);
- FUNC3(body_add_shape, RID, RID, const Transform2D &);
+ FUNC4(body_add_shape, RID, RID, const Transform2D &, bool);
FUNC3(body_set_shape, RID, int, RID);
FUNC3(body_set_shape_transform, RID, int, const Transform2D &);
FUNC3(body_set_shape_metadata, RID, int, const Variant &);
diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp
index 56b87f620c..66d2dcd417 100644
--- a/servers/physics_2d/shape_2d_sw.cpp
+++ b/servers/physics_2d/shape_2d_sw.cpp
@@ -586,7 +586,7 @@ bool ConvexPolygonShape2DSW::contains_point(const Vector2 &p_point) const {
in = true;
}
- return (in && !out) || (!in && out);
+ return in != out;
}
bool ConvexPolygonShape2DSW::intersect_segment(const Vector2 &p_begin, const Vector2 &p_end, Vector2 &r_point, Vector2 &r_normal) const {
diff --git a/servers/physics_2d/space_2d_sw.cpp b/servers/physics_2d/space_2d_sw.cpp
index 831764b40c..f5acadd71c 100644
--- a/servers/physics_2d/space_2d_sw.cpp
+++ b/servers/physics_2d/space_2d_sw.cpp
@@ -333,10 +333,8 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D &
CollisionSolver2DSW::CallbackResult cbkres = NULL;
Physics2DServerSW::CollCbkData *cbkptr = NULL;
- if (p_result_max > 0) {
- cbkptr = &cbk;
- cbkres = Physics2DServerSW::_shape_col_cbk;
- }
+ cbkptr = &cbk;
+ cbkres = Physics2DServerSW::_shape_col_cbk;
for (int i = 0; i < amount; i++) {
@@ -353,7 +351,7 @@ bool Physics2DDirectSpaceStateSW::collide_shape(RID p_shape, const Transform2D &
cbk.valid_depth = 0;
if (CollisionSolver2DSW::solve(shape, p_shape_xform, p_motion, col_obj->get_shape(shape_idx), col_obj->get_transform() * col_obj->get_shape_transform(shape_idx), Vector2(), cbkres, cbkptr, NULL, p_margin)) {
- collided = p_result_max == 0 || cbk.amount > 0;
+ collided = cbk.amount > 0;
}
}
diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp
index 3a05791f17..dadadf68fd 100644
--- a/servers/physics_2d_server.cpp
+++ b/servers/physics_2d_server.cpp
@@ -567,10 +567,10 @@ void Physics2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &Physics2DServer::area_set_space_override_mode);
ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &Physics2DServer::area_get_space_override_mode);
- ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform"), &Physics2DServer::area_add_shape, DEFVAL(Transform2D()));
+ ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &Physics2DServer::area_add_shape, DEFVAL(Transform2D()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &Physics2DServer::area_set_shape);
ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &Physics2DServer::area_set_shape_transform);
- ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disable"), &Physics2DServer::area_set_shape_disabled);
+ ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disabled"), &Physics2DServer::area_set_shape_disabled);
ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &Physics2DServer::area_get_shape_count);
ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &Physics2DServer::area_get_shape);
@@ -606,7 +606,7 @@ void Physics2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_mode", "body", "mode"), &Physics2DServer::body_set_mode);
ClassDB::bind_method(D_METHOD("body_get_mode", "body"), &Physics2DServer::body_get_mode);
- ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform"), &Physics2DServer::body_add_shape, DEFVAL(Transform2D()));
+ ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &Physics2DServer::body_add_shape, DEFVAL(Transform2D()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &Physics2DServer::body_set_shape);
ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &Physics2DServer::body_set_shape_transform);
ClassDB::bind_method(D_METHOD("body_set_shape_metadata", "body", "shape_idx", "metadata"), &Physics2DServer::body_set_shape_metadata);
@@ -619,7 +619,7 @@ void Physics2DServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_remove_shape", "body", "shape_idx"), &Physics2DServer::body_remove_shape);
ClassDB::bind_method(D_METHOD("body_clear_shapes", "body"), &Physics2DServer::body_clear_shapes);
- ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disable"), &Physics2DServer::body_set_shape_disabled);
+ ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disabled"), &Physics2DServer::body_set_shape_disabled);
ClassDB::bind_method(D_METHOD("body_set_shape_as_one_way_collision", "body", "shape_idx", "enable", "margin"), &Physics2DServer::body_set_shape_as_one_way_collision);
ClassDB::bind_method(D_METHOD("body_attach_object_instance_id", "body", "id"), &Physics2DServer::body_attach_object_instance_id);
diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h
index 1de9c7df93..a9b95fbdf8 100644
--- a/servers/physics_2d_server.h
+++ b/servers/physics_2d_server.h
@@ -335,7 +335,7 @@ public:
virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0;
virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D()) = 0;
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0;
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0;
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform2D &p_transform) = 0;
@@ -388,7 +388,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0;
virtual BodyMode body_get_mode(RID p_body) const = 0;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D()) = 0;
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform2D &p_transform = Transform2D(), bool p_disabled = false) = 0;
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0;
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform2D &p_transform) = 0;
virtual void body_set_shape_metadata(RID p_body, int p_shape_idx, const Variant &p_metadata) = 0;
@@ -653,6 +653,12 @@ class Physics2DServerManager {
ClassInfo(const ClassInfo &p_ci) :
name(p_ci.name),
create_callback(p_ci.create_callback) {}
+
+ ClassInfo operator=(const ClassInfo &p_ci) {
+ name = p_ci.name;
+ create_callback = p_ci.create_callback;
+ return *this;
+ }
};
static Vector<ClassInfo> physics_2d_servers;
diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp
index 0629af663e..fe8c644f0b 100644
--- a/servers/physics_server.cpp
+++ b/servers/physics_server.cpp
@@ -427,9 +427,10 @@ void PhysicsServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("area_set_space_override_mode", "area", "mode"), &PhysicsServer::area_set_space_override_mode);
ClassDB::bind_method(D_METHOD("area_get_space_override_mode", "area"), &PhysicsServer::area_get_space_override_mode);
- ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform"), &PhysicsServer::area_add_shape, DEFVAL(Transform()));
+ ClassDB::bind_method(D_METHOD("area_add_shape", "area", "shape", "transform", "disabled"), &PhysicsServer::area_add_shape, DEFVAL(Transform()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("area_set_shape", "area", "shape_idx", "shape"), &PhysicsServer::area_set_shape);
ClassDB::bind_method(D_METHOD("area_set_shape_transform", "area", "shape_idx", "transform"), &PhysicsServer::area_set_shape_transform);
+ ClassDB::bind_method(D_METHOD("area_set_shape_disabled", "area", "shape_idx", "disabled"), &PhysicsServer::area_set_shape_disabled);
ClassDB::bind_method(D_METHOD("area_get_shape_count", "area"), &PhysicsServer::area_get_shape_count);
ClassDB::bind_method(D_METHOD("area_get_shape", "area", "shape_idx"), &PhysicsServer::area_get_shape);
@@ -471,9 +472,10 @@ void PhysicsServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("body_set_collision_mask", "body", "mask"), &PhysicsServer::body_set_collision_mask);
ClassDB::bind_method(D_METHOD("body_get_collision_mask", "body"), &PhysicsServer::body_get_collision_mask);
- ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform"), &PhysicsServer::body_add_shape, DEFVAL(Transform()));
+ ClassDB::bind_method(D_METHOD("body_add_shape", "body", "shape", "transform", "disabled"), &PhysicsServer::body_add_shape, DEFVAL(Transform()), DEFVAL(false));
ClassDB::bind_method(D_METHOD("body_set_shape", "body", "shape_idx", "shape"), &PhysicsServer::body_set_shape);
ClassDB::bind_method(D_METHOD("body_set_shape_transform", "body", "shape_idx", "transform"), &PhysicsServer::body_set_shape_transform);
+ ClassDB::bind_method(D_METHOD("body_set_shape_disabled", "body", "shape_idx", "disabled"), &PhysicsServer::body_set_shape_disabled);
ClassDB::bind_method(D_METHOD("body_get_shape_count", "body"), &PhysicsServer::body_get_shape_count);
ClassDB::bind_method(D_METHOD("body_get_shape", "body", "shape_idx"), &PhysicsServer::body_get_shape);
diff --git a/servers/physics_server.h b/servers/physics_server.h
index c71bb01943..bc196c11fb 100644
--- a/servers/physics_server.h
+++ b/servers/physics_server.h
@@ -320,7 +320,7 @@ public:
virtual void area_set_space_override_mode(RID p_area, AreaSpaceOverrideMode p_mode) = 0;
virtual AreaSpaceOverrideMode area_get_space_override_mode(RID p_area) const = 0;
- virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform()) = 0;
+ virtual void area_add_shape(RID p_area, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0;
virtual void area_set_shape(RID p_area, int p_shape_idx, RID p_shape) = 0;
virtual void area_set_shape_transform(RID p_area, int p_shape_idx, const Transform &p_transform) = 0;
@@ -372,7 +372,7 @@ public:
virtual void body_set_mode(RID p_body, BodyMode p_mode) = 0;
virtual BodyMode body_get_mode(RID p_body) const = 0;
- virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform()) = 0;
+ virtual void body_add_shape(RID p_body, RID p_shape, const Transform &p_transform = Transform(), bool p_disabled = false) = 0;
virtual void body_set_shape(RID p_body, int p_shape_idx, RID p_shape) = 0;
virtual void body_set_shape_transform(RID p_body, int p_shape_idx, const Transform &p_transform) = 0;
@@ -794,6 +794,12 @@ class PhysicsServerManager {
ClassInfo(const ClassInfo &p_ci) :
name(p_ci.name),
create_callback(p_ci.create_callback) {}
+
+ ClassInfo operator=(const ClassInfo &p_ci) {
+ name = p_ci.name;
+ create_callback = p_ci.create_callback;
+ return *this;
+ }
};
static Vector<ClassInfo> physics_servers;
diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp
index 0cc1cc119c..f3394019f5 100644
--- a/servers/register_server_types.cpp
+++ b/servers/register_server_types.cpp
@@ -50,7 +50,9 @@
#include "audio/effects/audio_effect_pitch_shift.h"
#include "audio/effects/audio_effect_record.h"
#include "audio/effects/audio_effect_reverb.h"
+#include "audio/effects/audio_effect_spectrum_analyzer.h"
#include "audio/effects/audio_effect_stereo_enhance.h"
+#include "audio/effects/audio_stream_generator.h"
#include "audio_server.h"
#include "core/script_debugger_remote.h"
#include "physics/physics_server_sw.h"
@@ -120,13 +122,18 @@ void register_server_types() {
ClassDB::register_virtual_class<AudioStream>();
ClassDB::register_virtual_class<AudioStreamPlayback>();
+ ClassDB::register_virtual_class<AudioStreamPlaybackResampled>();
ClassDB::register_class<AudioStreamMicrophone>();
ClassDB::register_class<AudioStreamRandomPitch>();
ClassDB::register_virtual_class<AudioEffect>();
+ ClassDB::register_virtual_class<AudioEffectInstance>();
ClassDB::register_class<AudioEffectEQ>();
ClassDB::register_class<AudioEffectFilter>();
ClassDB::register_class<AudioBusLayout>();
+ ClassDB::register_class<AudioStreamGenerator>();
+ ClassDB::register_virtual_class<AudioStreamGeneratorPlayback>();
+
{
//audio effects
ClassDB::register_class<AudioEffectAmplify>();
@@ -156,7 +163,10 @@ void register_server_types() {
ClassDB::register_class<AudioEffectLimiter>();
ClassDB::register_class<AudioEffectPitchShift>();
ClassDB::register_class<AudioEffectPhaser>();
+
ClassDB::register_class<AudioEffectRecord>();
+ ClassDB::register_class<AudioEffectSpectrumAnalyzer>();
+ ClassDB::register_virtual_class<AudioEffectSpectrumAnalyzerInstance>();
}
ClassDB::register_virtual_class<Physics2DDirectBodyState>();
diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h
index dd54698471..a02f52f034 100644
--- a/servers/visual/rasterizer.h
+++ b/servers/visual/rasterizer.h
@@ -373,6 +373,7 @@ public:
virtual void light_set_negative(RID p_light, bool p_enable) = 0;
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
+ virtual void light_set_use_gi(RID p_light, bool p_enable) = 0;
virtual void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) = 0;
virtual void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail) = 0;
@@ -392,6 +393,7 @@ public:
virtual AABB light_get_aabb(RID p_light) const = 0;
virtual float light_get_param(RID p_light, VS::LightParam p_param) = 0;
virtual Color light_get_color(RID p_light) = 0;
+ virtual bool light_get_use_gi(RID p_light) = 0;
virtual uint64_t light_get_version(RID p_light) const = 0;
/* PROBE API */
@@ -554,6 +556,7 @@ public:
virtual RID render_target_create() = 0;
virtual void render_target_set_size(RID p_render_target, int p_width, int p_height) = 0;
virtual RID render_target_get_texture(RID p_render_target) const = 0;
+ virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) = 0;
virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) = 0;
virtual bool render_target_was_used(RID p_render_target) = 0;
virtual void render_target_clear_used(RID p_render_target) = 0;
@@ -788,6 +791,8 @@ public:
RID mesh;
RID texture;
RID normal_map;
+ Transform2D transform;
+ Color modulate;
CommandMesh() { type = TYPE_MESH; }
};
@@ -1101,7 +1106,7 @@ public:
virtual void initialize() = 0;
virtual void begin_frame(double frame_step) = 0;
virtual void set_current_render_target(RID p_render_target) = 0;
- virtual void restore_render_target() = 0;
+ virtual void restore_render_target(bool p_3d) = 0;
virtual void clear_render_target(const Color &p_color) = 0;
virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) = 0;
virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) = 0;
diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp
index 1f9d263354..33714a79b2 100644
--- a/servers/visual/shader_language.cpp
+++ b/servers/visual/shader_language.cpp
@@ -3620,7 +3620,8 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha
case TYPE_FLOAT: {
nv.real = -cn->values[i].real;
} break;
- default: {}
+ default: {
+ }
}
values.push_back(nv);
@@ -4822,7 +4823,8 @@ Error ShaderLanguage::complete(const String &p_code, const Map<StringName, Funct
case TYPE_MAT2: limit = 2; break;
case TYPE_MAT3: limit = 3; break;
case TYPE_MAT4: limit = 4; break;
- default: {}
+ default: {
+ }
}
for (int i = 0; i < limit; i++) {
diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp
index 85dcaa6b03..d5e154a7fc 100644
--- a/servers/visual/visual_server_canvas.cpp
+++ b/servers/visual/visual_server_canvas.cpp
@@ -33,11 +33,9 @@
#include "visual_server_raster.h"
#include "visual_server_viewport.h"
-void VisualServerCanvas::_render_canvas_item_tree(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) {
+static const int z_range = VS::CANVAS_ITEM_Z_MAX - VS::CANVAS_ITEM_Z_MIN + 1;
- static const int z_range = VS::CANVAS_ITEM_Z_MAX - VS::CANVAS_ITEM_Z_MIN + 1;
- RasterizerCanvas::Item *z_list[z_range];
- RasterizerCanvas::Item *z_last_list[z_range];
+void VisualServerCanvas::_render_canvas_item_tree(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights) {
memset(z_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
memset(z_last_list, 0, z_range * sizeof(RasterizerCanvas::Item *));
@@ -51,20 +49,23 @@ void VisualServerCanvas::_render_canvas_item_tree(Item *p_canvas_item, const Tra
}
}
-void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2D p_transform, VisualServerCanvas::Item **r_items, int &r_index) {
+void _collect_ysort_children(VisualServerCanvas::Item *p_canvas_item, Transform2D p_transform, VisualServerCanvas::Item *p_material_owner, VisualServerCanvas::Item **r_items, int &r_index) {
int child_item_count = p_canvas_item->child_items.size();
VisualServerCanvas::Item **child_items = p_canvas_item->child_items.ptrw();
for (int i = 0; i < child_item_count; i++) {
- if (r_items) {
- r_items[r_index] = child_items[i];
- child_items[i]->ysort_xform = p_transform;
- child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.elements[2]);
- }
+ if (child_items[i]->visible) {
+ if (r_items) {
+ r_items[r_index] = child_items[i];
+ child_items[i]->ysort_xform = p_transform;
+ child_items[i]->ysort_pos = p_transform.xform(child_items[i]->xform.elements[2]);
+ child_items[i]->material_owner = child_items[i]->use_parent_material ? p_material_owner : NULL;
+ }
- r_index++;
+ r_index++;
- if (child_items[i]->sort_y)
- _collect_ysort_children(child_items[i], p_transform * child_items[i]->xform, r_items, 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], r_items, r_index);
+ }
}
}
@@ -124,14 +125,14 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor
if (ci->ysort_children_count == -1) {
ci->ysort_children_count = 0;
- _collect_ysort_children(ci, Transform2D(), NULL, ci->ysort_children_count);
+ _collect_ysort_children(ci, Transform2D(), p_material_owner, NULL, ci->ysort_children_count);
}
child_item_count = ci->ysort_children_count;
child_items = (Item **)alloca(child_item_count * sizeof(Item *));
int i = 0;
- _collect_ysort_children(ci, Transform2D(), child_items, i);
+ _collect_ysort_children(ci, Transform2D(), p_material_owner, child_items, i);
SortArray<Item *, ItemPtrSort> sorter;
sorter.sort(child_items, child_item_count);
@@ -147,7 +148,7 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor
if (!child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y))
continue;
if (ci->sort_y) {
- _render_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
+ _render_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
} else {
_render_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
}
@@ -189,7 +190,7 @@ void VisualServerCanvas::_render_canvas_item(Item *p_canvas_item, const Transfor
if (child_items[i]->behind || (ci->sort_y && child_items[i]->sort_y))
continue;
if (ci->sort_y) {
- _render_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
+ _render_canvas_item(child_items[i], xform * child_items[i]->ysort_xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, (Item *)child_items[i]->material_owner);
} else {
_render_canvas_item(child_items[i], xform, p_clip_rect, modulate, p_z, z_list, z_last_list, (Item *)ci->final_clip_owner, p_material_owner);
}
@@ -319,6 +320,19 @@ void VisualServerCanvas::canvas_set_modulate(RID p_canvas, const Color &p_color)
canvas->modulate = p_color;
}
+void VisualServerCanvas::canvas_set_disable_scale(bool p_disable) {
+ disable_scale = p_disable;
+}
+
+void VisualServerCanvas::canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) {
+
+ Canvas *canvas = canvas_owner.get(p_canvas);
+ ERR_FAIL_COND(!canvas);
+
+ canvas->parent = p_parent;
+ canvas->parent_scale = p_scale;
+}
+
RID VisualServerCanvas::canvas_item_create() {
Item *canvas_item = memnew(Item);
@@ -380,6 +394,10 @@ void VisualServerCanvas::canvas_item_set_visible(RID p_item, bool p_visible) {
ERR_FAIL_COND(!canvas_item);
canvas_item->visible = p_visible;
+
+ if (canvas_item->parent.is_valid() && canvas_item_owner.owns(canvas_item->parent)) {
+ _mark_ysort_dirty(canvas_item_owner.get(canvas_item->parent), canvas_item_owner);
+ }
}
void VisualServerCanvas::canvas_item_set_light_mask(RID p_item, int p_mask) {
@@ -616,7 +634,7 @@ void VisualServerCanvas::canvas_item_add_texture_rect(RID p_item, const Rect2 &p
if (p_tile) {
rect->flags |= RasterizerCanvas::CANVAS_RECT_TILE;
rect->flags |= RasterizerCanvas::CANVAS_RECT_REGION;
- rect->source = Rect2(0, 0, p_rect.size.width, p_rect.size.height);
+ rect->source = Rect2(0, 0, fabsf(p_rect.size.width), fabsf(p_rect.size.height));
}
if (p_rect.size.x < 0) {
@@ -810,7 +828,7 @@ void VisualServerCanvas::canvas_item_add_set_transform(RID p_item, const Transfo
canvas_item->commands.push_back(tr);
}
-void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture, RID p_normal_map) {
+void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform, const Color &p_modulate, RID p_texture, RID p_normal_map) {
Item *canvas_item = canvas_item_owner.getornull(p_item);
ERR_FAIL_COND(!canvas_item);
@@ -820,6 +838,8 @@ void VisualServerCanvas::canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID
m->mesh = p_mesh;
m->texture = p_texture;
m->normal_map = p_normal_map;
+ m->transform = p_transform;
+ m->modulate = p_modulate;
canvas_item->commands.push_back(m);
}
@@ -1434,4 +1454,15 @@ bool VisualServerCanvas::free(RID p_rid) {
}
VisualServerCanvas::VisualServerCanvas() {
+
+ z_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
+ z_last_list = (RasterizerCanvas::Item **)memalloc(z_range * sizeof(RasterizerCanvas::Item *));
+
+ disable_scale = false;
+}
+
+VisualServerCanvas::~VisualServerCanvas() {
+
+ memfree(z_list);
+ memfree(z_last_list);
}
diff --git a/servers/visual/visual_server_canvas.h b/servers/visual/visual_server_canvas.h
index 7d788cbe14..26424f927e 100644
--- a/servers/visual/visual_server_canvas.h
+++ b/servers/visual/visual_server_canvas.h
@@ -82,7 +82,7 @@ public:
_FORCE_INLINE_ bool operator()(const Item *p_left, const Item *p_right) const {
- if (Math::abs(p_left->ysort_pos.y - p_right->ysort_pos.y) < CMP_EPSILON)
+ if (Math::is_equal_approx(p_left->ysort_pos.y, p_right->ysort_pos.y))
return p_left->ysort_pos.x < p_right->ysort_pos.x;
else
return p_left->ysort_pos.y < p_right->ysort_pos.y;
@@ -126,6 +126,8 @@ public:
bool children_order_dirty;
Vector<ChildItem> child_items;
Color modulate;
+ RID parent;
+ float parent_scale;
int find_item(Item *p_item) {
for (int i = 0; i < child_items.size(); i++) {
@@ -143,24 +145,32 @@ public:
Canvas() {
modulate = Color(1, 1, 1, 1);
children_order_dirty = true;
+ parent_scale = 1.0;
}
};
- RID_Owner<Canvas> canvas_owner;
+ mutable RID_Owner<Canvas> canvas_owner;
RID_Owner<Item> canvas_item_owner;
RID_Owner<RasterizerCanvas::Light> canvas_light_owner;
+ bool disable_scale;
+
private:
void _render_canvas_item_tree(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, RasterizerCanvas::Light *p_lights);
void _render_canvas_item(Item *p_canvas_item, const Transform2D &p_transform, const Rect2 &p_clip_rect, const Color &p_modulate, int p_z, RasterizerCanvas::Item **z_list, RasterizerCanvas::Item **z_last_list, Item *p_canvas_clip, Item *p_material_owner);
void _light_mask_canvas_items(int p_z, RasterizerCanvas::Item *p_canvas_item, RasterizerCanvas::Light *p_masked_lights);
+ RasterizerCanvas::Item **z_list;
+ RasterizerCanvas::Item **z_last_list;
+
public:
void render_canvas(Canvas *p_canvas, const Transform2D &p_transform, RasterizerCanvas::Light *p_lights, RasterizerCanvas::Light *p_masked_lights, const Rect2 &p_clip_rect);
RID canvas_create();
void canvas_set_item_mirroring(RID p_canvas, RID p_item, const Point2 &p_mirroring);
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);
RID canvas_item_create();
void canvas_item_set_parent(RID p_item, RID p_parent);
@@ -190,7 +200,7 @@ public:
void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID());
void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false);
void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID());
- void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID());
+ void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID());
void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID());
void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal);
void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform);
@@ -247,6 +257,7 @@ public:
bool free(RID p_rid);
VisualServerCanvas();
+ ~VisualServerCanvas();
};
#endif // VISUALSERVERCANVAS_H
diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h
index a1204c7573..3ec428d687 100644
--- a/servers/visual/visual_server_raster.h
+++ b/servers/visual/visual_server_raster.h
@@ -312,6 +312,7 @@ public:
BIND2(light_set_negative, RID, bool)
BIND2(light_set_cull_mask, RID, uint32_t)
BIND2(light_set_reverse_cull_face_mode, RID, bool)
+ BIND2(light_set_use_gi, RID, bool)
BIND2(light_omni_set_shadow_mode, RID, LightOmniShadowMode)
BIND2(light_omni_set_shadow_detail, RID, LightOmniShadowDetail)
@@ -430,6 +431,7 @@ public:
BIND0R(RID, camera_create)
BIND4(camera_set_perspective, RID, float, float, float)
BIND4(camera_set_orthogonal, RID, float, float, float)
+ BIND5(camera_set_frustum, RID, float, Vector2, float, float)
BIND2(camera_set_transform, RID, const Transform &)
BIND2(camera_set_cull_mask, RID, uint32_t)
BIND2(camera_set_environment, RID, RID)
@@ -569,6 +571,8 @@ public:
BIND0R(RID, canvas_create)
BIND3(canvas_set_item_mirroring, RID, RID, const Point2 &)
BIND2(canvas_set_modulate, RID, const Color &)
+ BIND3(canvas_set_parent, RID, RID, float)
+ BIND1(canvas_set_disable_scale, bool)
BIND0R(RID, canvas_item_create)
BIND2(canvas_item_set_parent, RID, RID)
@@ -598,7 +602,7 @@ public:
BIND7(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID)
BIND7(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, bool)
BIND10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID)
- BIND4(canvas_item_add_mesh, RID, const RID &, RID, RID)
+ BIND6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID)
BIND4(canvas_item_add_multimesh, RID, RID, RID, RID)
BIND4(canvas_item_add_particles, RID, RID, RID, RID)
BIND2(canvas_item_add_set_transform, RID, const Transform2D &)
diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp
index 2590e29aef..bce5eaf7b0 100644
--- a/servers/visual/visual_server_scene.cpp
+++ b/servers/visual/visual_server_scene.cpp
@@ -61,6 +61,16 @@ void VisualServerScene::camera_set_orthogonal(RID p_camera, float p_size, float
camera->zfar = p_z_far;
}
+void VisualServerScene::camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) {
+ Camera *camera = camera_owner.get(p_camera);
+ ERR_FAIL_COND(!camera);
+ camera->type = Camera::FRUSTUM;
+ camera->size = p_size;
+ camera->offset = p_offset;
+ camera->znear = p_z_near;
+ camera->zfar = p_z_far;
+}
+
void VisualServerScene::camera_set_transform(RID p_camera, const Transform &p_transform) {
Camera *camera = camera_owner.get(p_camera);
@@ -399,7 +409,8 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
VSG::scene_render->free(gi_probe->probe_instance);
} break;
- default: {}
+ default: {
+ }
}
if (instance->base_data) {
@@ -476,7 +487,8 @@ void VisualServerScene::instance_set_base(RID p_instance, RID p_base) {
gi_probe->probe_instance = VSG::scene_render->gi_probe_instance_create();
} break;
- default: {}
+ default: {
+ }
}
VSG::storage->instance_add_dependency(p_base, instance);
@@ -524,7 +536,8 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) {
gi_probe_update_list.remove(&gi_probe->update_element);
}
} break;
- default: {}
+ default: {
+ }
}
instance->scenario = NULL;
@@ -556,7 +569,8 @@ void VisualServerScene::instance_set_scenario(RID p_instance, RID p_scenario) {
gi_probe_update_list.add(&gi_probe->update_element);
}
} break;
- default: {}
+ default: {
+ }
}
_instance_queue_update(instance, true, true);
@@ -671,7 +685,8 @@ void VisualServerScene::instance_set_visible(RID p_instance, bool p_visible) {
}
} break;
- default: {}
+ default: {
+ }
}
}
inline bool is_geometry_instance(VisualServer::InstanceType p_type) {
@@ -848,7 +863,8 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF
instance->redraw_if_visible = p_enabled;
} break;
- default: {}
+ default: {
+ }
}
}
void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) {
@@ -1040,7 +1056,8 @@ void VisualServerScene::_update_instance_aabb(Instance *p_instance) {
new_aabb = VSG::storage->lightmap_capture_get_bounds(p_instance->base);
} break;
- default: {}
+ default: {
+ }
}
// <Zylann> This is why I didn't re-use Instance::aabb to implement custom AABBs
@@ -1723,6 +1740,17 @@ void VisualServerScene::render_camera(RID p_camera, RID p_scenario, Size2 p_view
ortho = false;
} break;
+ case Camera::FRUSTUM: {
+
+ camera_matrix.set_frustum(
+ camera->size,
+ p_viewport_size.width / (float)p_viewport_size.height,
+ camera->offset,
+ camera->znear,
+ camera->zfar,
+ camera->vaspect);
+ ortho = false;
+ } break;
}
_prepare_scene(camera->transform, camera_matrix, ortho, camera->env, camera->visible_layers, p_scenario, p_shadow_atlas, RID());
@@ -1864,7 +1892,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
//failure
} else if (ins->base_type == VS::INSTANCE_LIGHT && ins->visible) {
- if (ins->visible && light_cull_count < MAX_LIGHTS_CULLED) {
+ if (light_cull_count < MAX_LIGHTS_CULLED) {
InstanceLightData *light = static_cast<InstanceLightData *>(ins->base_data);
@@ -1881,7 +1909,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca
}
} else if (ins->base_type == VS::INSTANCE_REFLECTION_PROBE && ins->visible) {
- if (ins->visible && reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED) {
+ if (reflection_probe_cull_count < MAX_REFLECTION_PROBES_CULLED) {
InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(ins->base_data);
@@ -2626,7 +2654,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
for (int i = 0; i < 3; i++) {
- if (ABS(light_axis[i]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[i]))
continue;
clip[clip_planes].normal[i] = 1.0;
@@ -2761,7 +2789,7 @@ void VisualServerScene::_bake_gi_probe_light(const GIProbeDataHeader *header, co
for (int c = 0; c < 3; c++) {
- if (ABS(light_axis[c]) < CMP_EPSILON)
+ if (Math::is_zero_approx(light_axis[c]))
continue;
clip[clip_planes].normal[c] = 1.0;
@@ -3089,6 +3117,9 @@ bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) {
for (List<Instance *>::Element *E = p_gi_probe->scenario->directional_lights.front(); E; E = E->next()) {
+ if (!VSG::storage->light_get_use_gi(E->get()->base))
+ continue;
+
InstanceGIProbeData::LightCache lc;
lc.type = VSG::storage->light_get_type(E->get()->base);
lc.color = VSG::storage->light_get_color(E->get()->base);
@@ -3109,6 +3140,9 @@ bool VisualServerScene::_check_gi_probe(Instance *p_gi_probe) {
for (Set<Instance *>::Element *E = probe_data->lights.front(); E; E = E->next()) {
+ if (!VSG::storage->light_get_use_gi(E->get()->base))
+ continue;
+
InstanceGIProbeData::LightCache lc;
lc.type = VSG::storage->light_get_type(E->get()->base);
lc.color = VSG::storage->light_get_color(E->get()->base);
diff --git a/servers/visual/visual_server_scene.h b/servers/visual/visual_server_scene.h
index 7583acd88f..2c2ba7e15f 100644
--- a/servers/visual/visual_server_scene.h
+++ b/servers/visual/visual_server_scene.h
@@ -77,12 +77,14 @@ public:
enum Type {
PERSPECTIVE,
- ORTHOGONAL
+ ORTHOGONAL,
+ FRUSTUM
};
Type type;
float fov;
float znear, zfar;
float size;
+ Vector2 offset;
uint32_t visible_layers;
bool vaspect;
RID env;
@@ -97,6 +99,7 @@ public:
znear = 0.05;
zfar = 100;
size = 1.0;
+ offset = Vector2();
vaspect = false;
}
};
@@ -106,6 +109,7 @@ public:
virtual RID camera_create();
virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far);
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far);
+ virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far);
virtual void camera_set_transform(RID p_camera, const Transform &p_transform);
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers);
virtual void camera_set_environment(RID p_camera, RID p_env);
diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp
index 2c6709662f..e7f60c2c1f 100644
--- a/servers/visual/visual_server_viewport.cpp
+++ b/servers/visual/visual_server_viewport.cpp
@@ -35,6 +35,43 @@
#include "visual_server_globals.h"
#include "visual_server_scene.h"
+static Transform2D _canvas_get_transform(VisualServerViewport::Viewport *p_viewport, VisualServerCanvas::Canvas *p_canvas, VisualServerViewport::Viewport::CanvasData *p_canvas_data, const Vector2 &p_vp_size) {
+
+ Transform2D xf = p_viewport->global_transform;
+
+ float scale = 1.0;
+ if (p_viewport->canvas_map.has(p_canvas->parent)) {
+ xf = xf * p_viewport->canvas_map[p_canvas->parent].transform;
+ scale = p_canvas->parent_scale;
+ }
+
+ xf = xf * p_canvas_data->transform;
+
+ if (scale != 1.0 && !VSG::canvas->disable_scale) {
+ Vector2 pivot = p_vp_size * 0.5;
+ Transform2D xfpivot;
+ xfpivot.set_origin(pivot);
+ Transform2D xfscale;
+ xfscale.scale(Vector2(scale, scale));
+
+ xf = xfpivot.affine_inverse() * xf;
+ xf = xfscale * xf;
+ xf = xfpivot * xf;
+ }
+
+ return xf;
+}
+
+void VisualServerViewport::_draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye) {
+ Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
+
+ if (p_viewport->use_arvr && arvr_interface.is_valid()) {
+ VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ } else {
+ VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ }
+}
+
void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye) {
/* Camera should always be BEFORE any other 3D */
@@ -62,13 +99,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
}
if (!scenario_draw_canvas_bg && can_draw_3d) {
- Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
- if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
- } else {
- VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
- }
+ _draw_3d(p_viewport, p_eye);
}
if (!p_viewport->hide_canvas) {
@@ -86,10 +117,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
for (Map<RID, Viewport::CanvasData>::Element *E = p_viewport->canvas_map.front(); E; E = E->next()) {
- Transform2D xf = p_viewport->global_transform * E->get().transform;
-
VisualServerCanvas::Canvas *canvas = static_cast<VisualServerCanvas::Canvas *>(E->get().canvas);
+ Transform2D xf = _canvas_get_transform(p_viewport, canvas, &E->get(), clip_rect.size);
+
//find lights in canvas
for (Set<RasterizerCanvas::Light *>::Element *F = canvas->lights.front(); F; F = F->next()) {
@@ -174,17 +205,13 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
//VSG::canvas_render->reset_canvas();
}
- VSG::rasterizer->restore_render_target();
+ VSG::rasterizer->restore_render_target(!scenario_draw_canvas_bg && can_draw_3d);
if (scenario_draw_canvas_bg && canvas_map.front() && canvas_map.front()->key().get_layer() > scenario_canvas_max_layer) {
- Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
if (!can_draw_3d) {
VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas);
- } else if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
} else {
- VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ _draw_3d(p_viewport, p_eye);
}
scenario_draw_canvas_bg = false;
}
@@ -193,7 +220,7 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
VisualServerCanvas::Canvas *canvas = static_cast<VisualServerCanvas::Canvas *>(E->get()->canvas);
- Transform2D xform = p_viewport->global_transform * E->get()->transform;
+ Transform2D xform = _canvas_get_transform(p_viewport, canvas, E->get(), clip_rect.size);
RasterizerCanvas::Light *canvas_lights = NULL;
@@ -210,14 +237,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
i++;
if (scenario_draw_canvas_bg && E->key().get_layer() >= scenario_canvas_max_layer) {
- Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
if (!can_draw_3d) {
VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas);
- } else if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
} else {
- VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ _draw_3d(p_viewport, p_eye);
}
scenario_draw_canvas_bg = false;
@@ -225,14 +248,10 @@ void VisualServerViewport::_draw_viewport(Viewport *p_viewport, ARVRInterface::E
}
if (scenario_draw_canvas_bg) {
- Ref<ARVRInterface> arvr_interface = ARVRServer::get_singleton()->get_primary_interface();
-
if (!can_draw_3d) {
VSG::scene->render_empty_scene(p_viewport->scenario, p_viewport->shadow_atlas);
- } else if (p_viewport->use_arvr && arvr_interface.is_valid()) {
- VSG::scene->render_camera(arvr_interface, p_eye, p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
} else {
- VSG::scene->render_camera(p_viewport->camera, p_viewport->scenario, p_viewport->size, p_viewport->shadow_atlas);
+ _draw_3d(p_viewport, p_eye);
}
scenario_draw_canvas_bg = false;
@@ -276,17 +295,27 @@ void VisualServerViewport::draw_viewports() {
if (vp->use_arvr && arvr_interface.is_valid()) {
// override our size, make sure it matches our required size
- Size2 size = arvr_interface->get_render_targetsize();
- VSG::storage->render_target_set_size(vp->render_target, size.x, size.y);
+ vp->size = arvr_interface->get_render_targetsize();
+ VSG::storage->render_target_set_size(vp->render_target, vp->size.x, vp->size.y);
// render mono or left eye first
ARVRInterface::Eyes leftOrMono = arvr_interface->is_stereo() ? ARVRInterface::EYE_LEFT : ARVRInterface::EYE_MONO;
+
+ // check for an external texture destination for our left eye/mono
+ VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(leftOrMono));
+
+ // set our render target as current
VSG::rasterizer->set_current_render_target(vp->render_target);
+
+ // and draw left eye/mono
_draw_viewport(vp, leftOrMono);
arvr_interface->commit_for_eye(leftOrMono, vp->render_target, vp->viewport_to_screen_rect);
// render right eye
if (leftOrMono == ARVRInterface::EYE_LEFT) {
+ // check for an external texture destination for our right eye
+ VSG::storage->render_target_set_external_texture(vp->render_target, arvr_interface->get_external_texture_for_eye(ARVRInterface::EYE_RIGHT));
+
// commit for eye may have changed the render target
VSG::rasterizer->set_current_render_target(vp->render_target);
@@ -297,6 +326,7 @@ void VisualServerViewport::draw_viewports() {
// and for our frame timing, mark when we've finished committing our eyes
ARVRServer::get_singleton()->_mark_commit();
} else {
+ VSG::storage->render_target_set_external_texture(vp->render_target, 0);
VSG::rasterizer->set_current_render_target(vp->render_target);
VSG::scene_render->set_debug_draw_mode(vp->debug_draw);
diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h
index 5176551540..555b40a103 100644
--- a/servers/visual/visual_server_viewport.h
+++ b/servers/visual/visual_server_viewport.h
@@ -147,6 +147,7 @@ public:
private:
Color clear_color;
+ void _draw_3d(Viewport *p_viewport, ARVRInterface::Eyes p_eye);
void _draw_viewport(Viewport *p_viewport, ARVRInterface::Eyes p_eye = ARVRInterface::EYE_MONO);
public:
diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h
index c6da6799a5..b2753369b8 100644
--- a/servers/visual/visual_server_wrap_mt.h
+++ b/servers/visual/visual_server_wrap_mt.h
@@ -248,6 +248,7 @@ public:
FUNC2(light_set_negative, RID, bool)
FUNC2(light_set_cull_mask, RID, uint32_t)
FUNC2(light_set_reverse_cull_face_mode, RID, bool)
+ FUNC2(light_set_use_gi, RID, bool)
FUNC2(light_omni_set_shadow_mode, RID, LightOmniShadowMode)
FUNC2(light_omni_set_shadow_detail, RID, LightOmniShadowDetail)
@@ -360,6 +361,7 @@ public:
FUNCRID(camera)
FUNC4(camera_set_perspective, RID, float, float, float)
FUNC4(camera_set_orthogonal, RID, float, float, float)
+ FUNC5(camera_set_frustum, RID, float, Vector2, float, float)
FUNC2(camera_set_transform, RID, const Transform &)
FUNC2(camera_set_cull_mask, RID, uint32_t)
FUNC2(camera_set_environment, RID, RID)
@@ -487,6 +489,8 @@ public:
FUNCRID(canvas)
FUNC3(canvas_set_item_mirroring, RID, RID, const Point2 &)
FUNC2(canvas_set_modulate, RID, const Color &)
+ FUNC3(canvas_set_parent, RID, RID, float)
+ FUNC1(canvas_set_disable_scale, bool)
FUNCRID(canvas_item)
FUNC2(canvas_item_set_parent, RID, RID)
@@ -516,7 +520,7 @@ public:
FUNC7(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float, RID)
FUNC7(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, RID, bool)
FUNC10(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int, RID)
- FUNC4(canvas_item_add_mesh, RID, const RID &, RID, RID)
+ FUNC6(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID, RID)
FUNC4(canvas_item_add_multimesh, RID, RID, RID, RID)
FUNC4(canvas_item_add_particles, RID, RID, RID, RID)
FUNC2(canvas_item_add_set_transform, RID, const Transform2D &)
diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp
index 19c6106502..b39b400a53 100644
--- a/servers/visual_server.cpp
+++ b/servers/visual_server.cpp
@@ -1780,6 +1780,7 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("light_set_negative", "light", "enable"), &VisualServer::light_set_negative);
ClassDB::bind_method(D_METHOD("light_set_cull_mask", "light", "mask"), &VisualServer::light_set_cull_mask);
ClassDB::bind_method(D_METHOD("light_set_reverse_cull_face_mode", "light", "enabled"), &VisualServer::light_set_reverse_cull_face_mode);
+ ClassDB::bind_method(D_METHOD("light_set_use_gi", "light", "enabled"), &VisualServer::light_set_use_gi);
ClassDB::bind_method(D_METHOD("light_omni_set_shadow_mode", "light", "mode"), &VisualServer::light_omni_set_shadow_mode);
ClassDB::bind_method(D_METHOD("light_omni_set_shadow_detail", "light", "detail"), &VisualServer::light_omni_set_shadow_detail);
@@ -1863,6 +1864,7 @@ void VisualServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("camera_create"), &VisualServer::camera_create);
ClassDB::bind_method(D_METHOD("camera_set_perspective", "camera", "fovy_degrees", "z_near", "z_far"), &VisualServer::camera_set_perspective);
ClassDB::bind_method(D_METHOD("camera_set_orthogonal", "camera", "size", "z_near", "z_far"), &VisualServer::camera_set_orthogonal);
+ ClassDB::bind_method(D_METHOD("camera_set_frustum", "camera", "size", "offset", "z_near", "z_far"), &VisualServer::camera_set_frustum);
ClassDB::bind_method(D_METHOD("camera_set_transform", "camera", "transform"), &VisualServer::camera_set_transform);
ClassDB::bind_method(D_METHOD("camera_set_cull_mask", "camera", "layers"), &VisualServer::camera_set_cull_mask);
ClassDB::bind_method(D_METHOD("camera_set_environment", "camera", "env"), &VisualServer::camera_set_environment);
diff --git a/servers/visual_server.h b/servers/visual_server.h
index 63ddc3328a..d40678c003 100644
--- a/servers/visual_server.h
+++ b/servers/visual_server.h
@@ -435,6 +435,7 @@ public:
virtual void light_set_negative(RID p_light, bool p_enable) = 0;
virtual void light_set_cull_mask(RID p_light, uint32_t p_mask) = 0;
virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) = 0;
+ virtual void light_set_use_gi(RID p_light, bool p_enable) = 0;
// omni light
enum LightOmniShadowMode {
@@ -584,6 +585,7 @@ public:
virtual RID camera_create() = 0;
virtual void camera_set_perspective(RID p_camera, float p_fovy_degrees, float p_z_near, float p_z_far) = 0;
virtual void camera_set_orthogonal(RID p_camera, float p_size, float p_z_near, float p_z_far) = 0;
+ virtual void camera_set_frustum(RID p_camera, float p_size, Vector2 p_offset, float p_z_near, float p_z_far) = 0;
virtual void camera_set_transform(RID p_camera, const Transform &p_transform) = 0;
virtual void camera_set_cull_mask(RID p_camera, uint32_t p_layers) = 0;
virtual void camera_set_environment(RID p_camera, RID p_env) = 0;
@@ -860,6 +862,9 @@ 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_modulate(RID p_canvas, const Color &p_color) = 0;
+ virtual void canvas_set_parent(RID p_canvas, RID p_parent, float p_scale) = 0;
+
+ virtual void canvas_set_disable_scale(bool p_disable) = 0;
virtual RID canvas_item_create() = 0;
virtual void canvas_item_set_parent(RID p_item, RID p_parent) = 0;
@@ -895,7 +900,7 @@ public:
virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0, RID p_normal_map = RID()) = 0;
virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID(), RID p_normal_map = RID(), bool p_antialiased = false) = 0;
virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1, RID p_normal_map = RID()) = 0;
- virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0;
+ virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID(), RID p_normal_map = RID()) = 0;
virtual void canvas_item_add_multimesh(RID p_item, RID p_mesh, RID p_texture = RID(), RID p_normal_map = RID()) = 0;
virtual void canvas_item_add_particles(RID p_item, RID p_particles, RID p_texture, RID p_normal_map) = 0;
virtual void canvas_item_add_set_transform(RID p_item, const Transform2D &p_transform) = 0;