diff options
Diffstat (limited to 'servers')
30 files changed, 773 insertions, 95 deletions
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_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/space_sw.cpp b/servers/physics/space_sw.cpp index 4ab92715f4..e52cc376c0 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_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/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/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 39530bbbee..b22e26f903 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -789,6 +789,8 @@ public: RID mesh; RID texture; RID normal_map; + Transform2D transform; + Color modulate; CommandMesh() { type = TYPE_MESH; } }; 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 4adf53c183..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); } @@ -393,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) { @@ -823,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); @@ -833,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); } @@ -1447,5 +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 8162085ced..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; @@ -160,6 +160,9 @@ private: 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); @@ -197,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); @@ -254,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 8ce25ba906..efe2a99d2e 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -430,6 +430,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) @@ -600,7 +601,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..af580d6794 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; 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 9ad3e4a308..e7f60c2c1f 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -295,8 +295,8 @@ 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; diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index efe251e9de..3e451511cd 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -360,6 +360,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) @@ -518,7 +519,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..041fb2b84f 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -1863,6 +1863,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 596b893b69..7693faf42b 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -584,6 +584,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; @@ -898,7 +899,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; |