diff options
Diffstat (limited to 'servers')
49 files changed, 1647 insertions, 232 deletions
diff --git a/servers/arvr/arvr_interface.h b/servers/arvr/arvr_interface.h index 0b922c5892..910b401db9 100644 --- a/servers/arvr/arvr_interface.h +++ b/servers/arvr/arvr_interface.h @@ -88,7 +88,7 @@ public: bool is_primary(); void set_is_primary(bool p_is_primary); - virtual bool is_initialized() = 0; /* returns true if we've initialized this interface */ + virtual bool is_initialized() const = 0; /* returns true if we've initialized this interface */ void set_is_initialized(bool p_initialized); /* helper function, will call initialize or uninitialize */ virtual bool initialize() = 0; /* initialize this interface, if this has an HMD it becomes the primary interface */ virtual void uninitialize() = 0; /* deinitialize this interface */ diff --git a/servers/arvr_server.cpp b/servers/arvr_server.cpp index f48bedbdac..0d1aad0dff 100644 --- a/servers/arvr_server.cpp +++ b/servers/arvr_server.cpp @@ -353,7 +353,7 @@ void ARVRServer::_process() { if (!interfaces[i].is_valid()) { // ignore, not a valid reference } else if (interfaces[i]->is_initialized()) { - interfaces[i]->process(); + interfaces.write[i]->process(); }; }; }; diff --git a/servers/audio/audio_effect.h b/servers/audio/audio_effect.h index cf732d4bdd..b950e824c0 100644 --- a/servers/audio/audio_effect.h +++ b/servers/audio/audio_effect.h @@ -39,6 +39,7 @@ class AudioEffectInstance : public Reference { public: virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) = 0; + virtual bool process_silence() const { return false; } }; class AudioEffect : public Resource { diff --git a/servers/audio/audio_rb_resampler.cpp b/servers/audio/audio_rb_resampler.cpp index 9faa4056c3..3414351681 100644 --- a/servers/audio/audio_rb_resampler.cpp +++ b/servers/audio/audio_rb_resampler.cpp @@ -100,6 +100,8 @@ uint32_t AudioRBResampler::_resample(AudioFrame *p_dest, int p_todo, int32_t p_i if (C == 6) { + // FIXME: Lot of unused assignments here, but it seems like intermediate calculations + // should be done as for C == 2 (C == 4 also has some unused assignments). float v0 = rb[(pos * 6) + 0]; float v1 = rb[(pos * 6) + 1]; float v2 = rb[(pos * 6) + 2]; diff --git a/servers/audio/audio_stream.cpp b/servers/audio/audio_stream.cpp index 113f23f8f2..eef8aba0c4 100644 --- a/servers/audio/audio_stream.cpp +++ b/servers/audio/audio_stream.cpp @@ -29,6 +29,7 @@ /*************************************************************************/ #include "audio_stream.h" +#include "os/os.h" ////////////////////////////// @@ -99,6 +100,119 @@ void AudioStream::_bind_methods() { //////////////////////////////// +Ref<AudioStreamPlayback> AudioStreamMicrophone::instance_playback() { + Ref<AudioStreamPlaybackMicrophone> playback; + playback.instance(); + + playbacks.insert(playback.ptr()); + + playback->microphone = Ref<AudioStreamMicrophone>((AudioStreamMicrophone *)this); + playback->active = false; + + return playback; +} + +String AudioStreamMicrophone::get_stream_name() const { + + //if (audio_stream.is_valid()) { + //return "Random: " + audio_stream->get_name(); + //} + return "Microphone"; +} + +float AudioStreamMicrophone::get_length() const { + return 0; +} + +void AudioStreamMicrophone::_bind_methods() { +} + +AudioStreamMicrophone::AudioStreamMicrophone() { +} + +void AudioStreamPlaybackMicrophone::_mix_internal(AudioFrame *p_buffer, int p_frames) { + + AudioDriver::get_singleton()->lock(); + + Vector<int32_t> buf = AudioDriver::get_singleton()->get_input_buffer(); + unsigned int input_size = AudioDriver::get_singleton()->get_input_size(); + + // p_frames is multipled by two since an AudioFrame is stereo + if ((p_frames + MICROPHONE_PLAYBACK_DELAY * 2) > input_size) { + for (int i = 0; i < p_frames; i++) { + p_buffer[i] = AudioFrame(0.0f, 0.0f); + } + input_ofs = 0; + } else { + for (int i = 0; i < p_frames; i++) { + if (input_size >= input_ofs) { + float l = (buf[input_ofs++] >> 16) / 32768.f; + if (input_ofs >= buf.size()) { + input_ofs = 0; + } + float r = (buf[input_ofs++] >> 16) / 32768.f; + if (input_ofs >= buf.size()) { + input_ofs = 0; + } + + p_buffer[i] = AudioFrame(l, r); + } else { + p_buffer[i] = AudioFrame(0.0f, 0.0f); + } + } + } + + AudioDriver::get_singleton()->unlock(); +} + +void AudioStreamPlaybackMicrophone::mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames) { + AudioStreamPlaybackResampled::mix(p_buffer, p_rate_scale, p_frames); +} + +float AudioStreamPlaybackMicrophone::get_stream_sampling_rate() { + return AudioDriver::get_singleton()->get_mix_rate(); +} + +void AudioStreamPlaybackMicrophone::start(float p_from_pos) { + input_ofs = 0; + + AudioDriver::get_singleton()->capture_start(); + + active = true; + _begin_resample(); +} + +void AudioStreamPlaybackMicrophone::stop() { + AudioDriver::get_singleton()->capture_stop(); + active = false; +} + +bool AudioStreamPlaybackMicrophone::is_playing() const { + return active; +} + +int AudioStreamPlaybackMicrophone::get_loop_count() const { + return 0; +} + +float AudioStreamPlaybackMicrophone::get_playback_position() const { + return 0; +} + +void AudioStreamPlaybackMicrophone::seek(float p_time) { + return; // Can't seek a microphone input +} + +AudioStreamPlaybackMicrophone::~AudioStreamPlaybackMicrophone() { + microphone->playbacks.erase(this); + stop(); +} + +AudioStreamPlaybackMicrophone::AudioStreamPlaybackMicrophone() { +} + +//////////////////////////////// + void AudioStreamRandomPitch::set_audio_stream(const Ref<AudioStream> &p_audio_stream) { audio_stream = p_audio_stream; diff --git a/servers/audio/audio_stream.h b/servers/audio/audio_stream.h index 3312ce1ff6..66e1b6ee2f 100644 --- a/servers/audio/audio_stream.h +++ b/servers/audio/audio_stream.h @@ -94,6 +94,63 @@ public: virtual float get_length() const = 0; //if supported, otherwise return 0 }; +// Microphone + +class AudioStreamPlaybackMicrophone; + +class AudioStreamMicrophone : public AudioStream { + + GDCLASS(AudioStreamMicrophone, AudioStream) + friend class AudioStreamPlaybackMicrophone; + + Set<AudioStreamPlaybackMicrophone *> playbacks; + +protected: + static void _bind_methods(); + +public: + virtual Ref<AudioStreamPlayback> instance_playback(); + virtual String get_stream_name() const; + + virtual float get_length() const; //if supported, otherwise return 0 + + AudioStreamMicrophone(); +}; + +class AudioStreamPlaybackMicrophone : public AudioStreamPlaybackResampled { + + GDCLASS(AudioStreamPlaybackMicrophone, AudioStreamPlayback) + friend class AudioStreamMicrophone; + + const int MICROPHONE_PLAYBACK_DELAY = 256; + + bool active; + unsigned int input_ofs; + + Ref<AudioStreamMicrophone> microphone; + +protected: + virtual void _mix_internal(AudioFrame *p_buffer, int p_frames); + virtual float get_stream_sampling_rate(); + +public: + virtual void mix(AudioFrame *p_buffer, float p_rate_scale, int p_frames); + + 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); + + ~AudioStreamPlaybackMicrophone(); + AudioStreamPlaybackMicrophone(); +}; + +// + class AudioStreamPlaybackRandomPitch; class AudioStreamRandomPitch : public AudioStream { diff --git a/servers/audio/effects/audio_effect_chorus.cpp b/servers/audio/effects/audio_effect_chorus.cpp index f2f554a09b..fd9e3311e7 100644 --- a/servers/audio/effects/audio_effect_chorus.cpp +++ b/servers/audio/effects/audio_effect_chorus.cpp @@ -53,7 +53,7 @@ void AudioEffectChorusInstance::_process_chunk(const AudioFrame *p_src_frames, A //fill ringbuffer for (int i = 0; i < p_frame_count; i++) { - audio_buffer[(buffer_pos + i) & buffer_mask] = p_src_frames[i]; + audio_buffer.write[(buffer_pos + i) & buffer_mask] = p_src_frames[i]; p_dst_frames[i] = p_src_frames[i] * base->dry; } @@ -175,7 +175,7 @@ Ref<AudioEffectInstance> AudioEffectChorus::instance() { ins->buffer_pos = 0; ins->audio_buffer.resize(ringbuff_size); for (int i = 0; i < ringbuff_size; i++) { - ins->audio_buffer[i] = AudioFrame(0, 0); + ins->audio_buffer.write[i] = AudioFrame(0, 0); } return ins; diff --git a/servers/audio/effects/audio_effect_eq.cpp b/servers/audio/effects/audio_effect_eq.cpp index a30fca4e8d..cf8f7d3e16 100644 --- a/servers/audio/effects/audio_effect_eq.cpp +++ b/servers/audio/effects/audio_effect_eq.cpp @@ -70,7 +70,7 @@ Ref<AudioEffectInstance> AudioEffectEQ::instance() { for (int i = 0; i < 2; i++) { ins->bands[i].resize(eq.get_band_count()); for (int j = 0; j < ins->bands[i].size(); j++) { - ins->bands[i][j] = eq.get_band_processor(j); + ins->bands[i].write[j] = eq.get_band_processor(j); } } @@ -79,7 +79,7 @@ Ref<AudioEffectInstance> AudioEffectEQ::instance() { void AudioEffectEQ::set_band_gain_db(int p_band, float p_volume) { ERR_FAIL_INDEX(p_band, gain.size()); - gain[p_band] = p_volume; + gain.write[p_band] = p_volume; } float AudioEffectEQ::get_band_gain_db(int p_band) const { @@ -134,7 +134,7 @@ AudioEffectEQ::AudioEffectEQ(EQ::Preset p_preset) { eq.set_preset_band_mode(p_preset); gain.resize(eq.get_band_count()); for (int i = 0; i < gain.size(); i++) { - gain[i] = 0.0; + gain.write[i] = 0.0; String name = "band_db/" + itos(eq.get_band_frequency(i)) + "_hz"; prop_band_map[name] = i; band_names.push_back(name); diff --git a/servers/audio/effects/audio_effect_record.cpp b/servers/audio/effects/audio_effect_record.cpp new file mode 100644 index 0000000000..74a6838d1a --- /dev/null +++ b/servers/audio/effects/audio_effect_record.cpp @@ -0,0 +1,264 @@ +/*************************************************************************/ +/* audio_effect_record.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#include "audio_effect_record.h" + +void AudioEffectRecordInstance::process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count) { + if (!is_recording) { + return; + } + + //Add incoming audio frames to the IO ring buffer + const AudioFrame *src = p_src_frames; + AudioFrame *rb_buf = ring_buffer.ptrw(); + for (int i = 0; i < p_frame_count; i++) { + rb_buf[ring_buffer_pos & ring_buffer_mask] = src[i]; + ring_buffer_pos++; + } +} + +bool AudioEffectRecordInstance::process_silence() { + return true; +} + +void AudioEffectRecordInstance::_io_thread_process() { + + //Reset recorder status + thread_active = true; + ring_buffer_pos = 0; + ring_buffer_read_pos = 0; + + //We start a new recording + recording_data.resize(0); //Clear data completely and reset length + is_recording = true; + + while (is_recording) { + //Check: The current recording has been requested to stop + if (is_recording && !base->recording_active) { + is_recording = false; + } + + //Case: Frames are remaining in the buffer + if (ring_buffer_read_pos < ring_buffer_pos) { + //Read from the buffer into recording_data + _io_store_buffer(); + } + //Case: The buffer is empty + else if (is_recording) { + //Wait to avoid too much busy-wait + OS::get_singleton()->delay_usec(500); + } + } + + thread_active = false; +} + +void AudioEffectRecordInstance::_io_store_buffer() { + int to_read = ring_buffer_pos - ring_buffer_read_pos; + + AudioFrame *rb_buf = ring_buffer.ptrw(); + + while (to_read) { + AudioFrame buffered_frame = rb_buf[ring_buffer_read_pos & ring_buffer_mask]; + recording_data.push_back(buffered_frame.l); + recording_data.push_back(buffered_frame.r); + + ring_buffer_read_pos++; + to_read--; + } +} + +void AudioEffectRecordInstance::_thread_callback(void *_instance) { + + AudioEffectRecordInstance *aeri = reinterpret_cast<AudioEffectRecordInstance *>(_instance); + + aeri->_io_thread_process(); +} + +void AudioEffectRecordInstance::init() { + io_thread = Thread::create(_thread_callback, this); +} + +Ref<AudioEffectInstance> AudioEffectRecord::instance() { + Ref<AudioEffectRecordInstance> ins; + ins.instance(); + ins->base = Ref<AudioEffectRecord>(this); + ins->is_recording = false; + + //Re-using the buffer size calculations from audio_effect_delay.cpp + float ring_buffer_max_size = IO_BUFFER_SIZE_MS; + ring_buffer_max_size /= 1000.0; //convert to seconds + ring_buffer_max_size *= AudioServer::get_singleton()->get_mix_rate(); + + int ringbuff_size = ring_buffer_max_size; + + int bits = 0; + + while (ringbuff_size > 0) { + bits++; + ringbuff_size /= 2; + } + + ringbuff_size = 1 << bits; + ins->ring_buffer_mask = ringbuff_size - 1; + ins->ring_buffer_pos = 0; + + ins->ring_buffer.resize(ringbuff_size); + + ins->ring_buffer_read_pos = 0; + + ensure_thread_stopped(); + current_instance = ins; + if (recording_active) { + ins->init(); + } + + return ins; +} + +void AudioEffectRecord::ensure_thread_stopped() { + recording_active = false; + if (current_instance != 0 && current_instance->thread_active) { + Thread::wait_to_finish(current_instance->io_thread); + } +} + +void AudioEffectRecord::set_recording_active(bool p_record) { + if (p_record) { + if (current_instance == 0) { + WARN_PRINTS("Recording should not be set as active before Godot has initialized."); + recording_active = false; + return; + } + + ensure_thread_stopped(); + current_instance->init(); + } + + recording_active = p_record; +} + +bool AudioEffectRecord::is_recording_active() const { + return recording_active; +} + +void AudioEffectRecord::set_format(AudioStreamSample::Format p_format) { + format = p_format; +} + +AudioStreamSample::Format AudioEffectRecord::get_format() const { + return format; +} + +Ref<AudioStreamSample> AudioEffectRecord::get_recording() const { + AudioStreamSample::Format dst_format = format; + bool stereo = true; //forcing mono is not implemented + + PoolVector<uint8_t> dst_data; + + if (dst_format == AudioStreamSample::FORMAT_8_BITS) { + int data_size = current_instance->recording_data.size(); + dst_data.resize(data_size); + PoolVector<uint8_t>::Write w = dst_data.write(); + + for (int i = 0; i < data_size; i++) { + int8_t v = CLAMP(current_instance->recording_data[i] * 128, -128, 127); + w[i] = v; + } + } else if (dst_format == AudioStreamSample::FORMAT_16_BITS) { + int data_size = current_instance->recording_data.size(); + dst_data.resize(data_size * 2); + PoolVector<uint8_t>::Write w = dst_data.write(); + + for (int i = 0; i < data_size; i++) { + int16_t v = CLAMP(current_instance->recording_data[i] * 32768, -32768, 32767); + encode_uint16(v, &w[i * 2]); + } + } else if (dst_format == AudioStreamSample::FORMAT_IMA_ADPCM) { + //byte interleave + Vector<float> left; + Vector<float> right; + + int tframes = current_instance->recording_data.size() / 2; + left.resize(tframes); + right.resize(tframes); + + for (int i = 0; i < tframes; i++) { + left.set(i, current_instance->recording_data[i * 2 + 0]); + right.set(i, current_instance->recording_data[i * 2 + 1]); + } + + PoolVector<uint8_t> bleft; + PoolVector<uint8_t> bright; + + ResourceImporterWAV::_compress_ima_adpcm(left, bleft); + ResourceImporterWAV::_compress_ima_adpcm(right, bright); + + int dl = bleft.size(); + dst_data.resize(dl * 2); + + PoolVector<uint8_t>::Write w = dst_data.write(); + PoolVector<uint8_t>::Read rl = bleft.read(); + PoolVector<uint8_t>::Read rr = bright.read(); + + for (int i = 0; i < dl; i++) { + w[i * 2 + 0] = rl[i]; + w[i * 2 + 1] = rr[i]; + } + } else { + ERR_EXPLAIN("format not implemented"); + } + + Ref<AudioStreamSample> sample; + sample.instance(); + sample->set_data(dst_data); + sample->set_format(dst_format); + sample->set_mix_rate(AudioServer::get_singleton()->get_mix_rate()); + sample->set_loop_mode(AudioStreamSample::LOOP_DISABLED); + sample->set_loop_begin(0); + sample->set_loop_end(0); + sample->set_stereo(stereo); + + return sample; +} + +void AudioEffectRecord::_bind_methods() { + ClassDB::bind_method(D_METHOD("set_recording_active", "record"), &AudioEffectRecord::set_recording_active); + ClassDB::bind_method(D_METHOD("is_recording_active"), &AudioEffectRecord::is_recording_active); + ClassDB::bind_method(D_METHOD("set_format", "format"), &AudioEffectRecord::set_format); + ClassDB::bind_method(D_METHOD("get_format"), &AudioEffectRecord::get_format); + ClassDB::bind_method(D_METHOD("get_recording"), &AudioEffectRecord::get_recording); + + ADD_PROPERTY(PropertyInfo(Variant::INT, "format", PROPERTY_HINT_ENUM, "8-Bit,16-Bit,IMA-ADPCM"), "set_format", "get_format"); +} + +AudioEffectRecord::AudioEffectRecord() { + format = AudioStreamSample::FORMAT_16_BITS; +} diff --git a/servers/audio/effects/audio_effect_record.h b/servers/audio/effects/audio_effect_record.h new file mode 100644 index 0000000000..e4f5ba8a23 --- /dev/null +++ b/servers/audio/effects/audio_effect_record.h @@ -0,0 +1,103 @@ +/*************************************************************************/ +/* audio_effect_record.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifndef AUDIOEFFECTRECORD_H +#define AUDIOEFFECTRECORD_H + +#include "core/os/thread.h" +#include "editor/import/resource_importer_wav.h" +#include "io/marshalls.h" +#include "os/file_access.h" +#include "os/os.h" +#include "scene/resources/audio_stream_sample.h" +#include "servers/audio/audio_effect.h" +#include "servers/audio_server.h" + +class AudioEffectRecord; + +class AudioEffectRecordInstance : public AudioEffectInstance { + GDCLASS(AudioEffectRecordInstance, AudioEffectInstance) + friend class AudioEffectRecord; + Ref<AudioEffectRecord> base; + + bool is_recording; + Thread *io_thread; + bool thread_active = false; + + Vector<AudioFrame> ring_buffer; + Vector<float> recording_data; + + unsigned int ring_buffer_pos; + unsigned int ring_buffer_mask; + unsigned int ring_buffer_read_pos; + + void _io_thread_process(); + void _io_store_buffer(); + static void _thread_callback(void *_instance); + void _init_recording(); + +public: + void init(); + virtual void process(const AudioFrame *p_src_frames, AudioFrame *p_dst_frames, int p_frame_count); + virtual bool process_silence(); +}; + +class AudioEffectRecord : public AudioEffect { + GDCLASS(AudioEffectRecord, AudioEffect) + + friend class AudioEffectRecordInstance; + + enum { + IO_BUFFER_SIZE_MS = 1500 + }; + + bool recording_active; + Ref<AudioEffectRecordInstance> current_instance; + + AudioStreamSample::Format format; + + void ensure_thread_stopped(); + +protected: + static void _bind_methods(); + static void debug(uint64_t time_diff, int p_frame_count); + +public: + Ref<AudioEffectInstance> instance(); + void set_recording_active(bool p_record); + bool is_recording_active() const; + void set_format(AudioStreamSample::Format p_format); + AudioStreamSample::Format get_format() const; + Ref<AudioStreamSample> get_recording() const; + + AudioEffectRecord(); +}; + +#endif // AUDIOEFFECTRECORD_H diff --git a/servers/audio/effects/eq.cpp b/servers/audio/effects/eq.cpp index 9ef41191f5..b15fc7ecf4 100644 --- a/servers/audio/effects/eq.cpp +++ b/servers/audio/effects/eq.cpp @@ -108,9 +108,9 @@ void EQ::recalculate_band_coefficients() { ERR_CONTINUE(roots == 0); - band[i].c1 = 2.0 * ((0.5 - r1) / 2.0); - band[i].c2 = 2.0 * r1; - band[i].c3 = 2.0 * (0.5 + r1) * cos(th); + band.write[i].c1 = 2.0 * ((0.5 - r1) / 2.0); + band.write[i].c2 = 2.0 * r1; + band.write[i].c3 = 2.0 * (0.5 + r1) * cos(th); //printf("band %i, coefs = %f,%f,%f\n",i,(float)bands[i].c1,(float)bands[i].c2,(float)bands[i].c3); } } @@ -180,7 +180,7 @@ void EQ::set_bands(const Vector<float> &p_bands) { band.resize(p_bands.size()); for (int i = 0; i < p_bands.size(); i++) { - band[i].freq = p_bands[i]; + band.write[i].freq = p_bands[i]; } recalculate_band_coefficients(); diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp index ceb843c031..14318f282b 100644 --- a/servers/audio_server.cpp +++ b/servers/audio_server.cpp @@ -33,6 +33,7 @@ #include "os/file_access.h" #include "os/os.h" #include "project_settings.h" +#include "scene/resources/audio_stream_sample.h" #include "servers/audio/audio_driver_dummy.h" #include "servers/audio/effects/audio_effect_compressor.h" #ifdef TOOLS_ENABLED @@ -79,6 +80,17 @@ double AudioDriver::get_mix_time() const { return total; } +void AudioDriver::input_buffer_write(int32_t sample) { + + input_buffer.write[input_position++] = sample; + if (input_position >= input_buffer.size()) { + input_position = 0; + } + if (input_size < input_buffer.size()) { + input_size++; + } +} + AudioDriver::SpeakerMode AudioDriver::get_speaker_mode_by_total_channels(int p_channels) const { switch (p_channels) { case 4: return SPEAKER_SURROUND_31; @@ -113,6 +125,14 @@ String AudioDriver::get_device() { return "Default"; } +Array AudioDriver::capture_get_device_list() { + Array list; + + list.push_back("Default"); + + return list; +} + AudioDriver::AudioDriver() { _last_mix_time = 0; @@ -264,7 +284,7 @@ void AudioServer::_mix_step() { bus->index_cache = i; //might be moved around by editor, so.. for (int k = 0; k < bus->channels.size(); k++) { - bus->channels[k].used = false; + bus->channels.write[k].used = false; } if (bus->solo) { @@ -310,7 +330,7 @@ void AudioServer::_mix_step() { if (bus->channels[k].active && !bus->channels[k].used) { //buffer was not used, but it's still active, so it must be cleaned - AudioFrame *buf = bus->channels[k].buffer.ptrw(); + AudioFrame *buf = bus->channels.write[k].buffer.ptrw(); for (uint32_t j = 0; j < buffer_size; j++) { @@ -332,21 +352,21 @@ void AudioServer::_mix_step() { for (int k = 0; k < bus->channels.size(); k++) { - if (!bus->channels[k].active) + if (!(bus->channels[k].active || bus->channels[k].effect_instances[j]->process_silence())) continue; - bus->channels[k].effect_instances[j]->process(bus->channels[k].buffer.ptr(), temp_buffer[k].ptrw(), buffer_size); + bus->channels.write[k].effect_instances.write[j]->process(bus->channels[k].buffer.ptr(), temp_buffer.write[k].ptrw(), buffer_size); } //swap buffers, so internal buffer always has the right data for (int k = 0; k < bus->channels.size(); k++) { - if (!buses[i]->channels[k].active) + if (!(buses[i]->channels[k].active || bus->channels[k].effect_instances[j]->process_silence())) continue; - SWAP(bus->channels[k].buffer, temp_buffer[k]); + SWAP(bus->channels.write[k].buffer, temp_buffer.write[k]); } #ifdef DEBUG_ENABLED - bus->effects[j].prof_time += OS::get_singleton()->get_ticks_usec() - ticks; + bus->effects.write[j].prof_time += OS::get_singleton()->get_ticks_usec() - ticks; #endif } } @@ -372,7 +392,7 @@ void AudioServer::_mix_step() { if (!bus->channels[k].active) continue; - AudioFrame *buf = bus->channels[k].buffer.ptrw(); + AudioFrame *buf = bus->channels.write[k].buffer.ptrw(); AudioFrame peak = AudioFrame(0, 0); @@ -403,15 +423,15 @@ void AudioServer::_mix_step() { } } - bus->channels[k].peak_volume = AudioFrame(Math::linear2db(peak.l + 0.0000000001), Math::linear2db(peak.r + 0.0000000001)); + bus->channels.write[k].peak_volume = AudioFrame(Math::linear2db(peak.l + 0.0000000001), Math::linear2db(peak.r + 0.0000000001)); if (!bus->channels[k].used) { //see if any audio is contained, because channel was not used if (MAX(peak.r, peak.l) > Math::db2linear(channel_disable_threshold_db)) { - bus->channels[k].last_mix_with_audio = mix_frames; + bus->channels.write[k].last_mix_with_audio = mix_frames; } else if (mix_frames - bus->channels[k].last_mix_with_audio > channel_disable_frames) { - bus->channels[k].active = false; + bus->channels.write[k].active = false; continue; //went inactive, don't mix. } } @@ -436,12 +456,12 @@ AudioFrame *AudioServer::thread_get_channel_mix_buffer(int p_bus, int p_buffer) ERR_FAIL_INDEX_V(p_bus, buses.size(), NULL); ERR_FAIL_INDEX_V(p_buffer, buses[p_bus]->channels.size(), NULL); - AudioFrame *data = buses[p_bus]->channels[p_buffer].buffer.ptrw(); + AudioFrame *data = buses.write[p_bus]->channels.write[p_buffer].buffer.ptrw(); if (!buses[p_bus]->channels[p_buffer].used) { - buses[p_bus]->channels[p_buffer].used = true; - buses[p_bus]->channels[p_buffer].active = true; - buses[p_bus]->channels[p_buffer].last_mix_with_audio = mix_frames; + buses.write[p_bus]->channels.write[p_buffer].used = true; + buses.write[p_bus]->channels.write[p_buffer].active = true; + buses.write[p_bus]->channels.write[p_buffer].last_mix_with_audio = mix_frames; for (uint32_t i = 0; i < buffer_size; i++) { data[i] = AudioFrame(0, 0); } @@ -506,10 +526,10 @@ void AudioServer::set_bus_count(int p_count) { } } - buses[i] = memnew(Bus); - buses[i]->channels.resize(channel_count); + buses.write[i] = memnew(Bus); + buses.write[i]->channels.resize(channel_count); for (int j = 0; j < channel_count; j++) { - buses[i]->channels[j].buffer.resize(buffer_size); + buses.write[i]->channels.write[j].buffer.resize(buffer_size); } buses[i]->name = attempt; buses[i]->solo = false; @@ -581,7 +601,7 @@ void AudioServer::add_bus(int p_at_pos) { Bus *bus = memnew(Bus); bus->channels.resize(channel_count); for (int j = 0; j < channel_count; j++) { - bus->channels[j].buffer.resize(buffer_size); + bus->channels.write[j].buffer.resize(buffer_size); } bus->name = attempt; bus->solo = false; @@ -764,13 +784,13 @@ bool AudioServer::is_bus_bypassing_effects(int p_bus) const { void AudioServer::_update_bus_effects(int p_bus) { for (int i = 0; i < buses[p_bus]->channels.size(); i++) { - buses[p_bus]->channels[i].effect_instances.resize(buses[p_bus]->effects.size()); + buses.write[p_bus]->channels.write[i].effect_instances.resize(buses[p_bus]->effects.size()); for (int j = 0; j < buses[p_bus]->effects.size(); j++) { - Ref<AudioEffectInstance> fx = buses[p_bus]->effects[j].effect->instance(); + Ref<AudioEffectInstance> fx = buses.write[p_bus]->effects.write[j].effect->instance(); if (Object::cast_to<AudioEffectCompressorInstance>(*fx)) { Object::cast_to<AudioEffectCompressorInstance>(*fx)->set_current_channel(i); } - buses[p_bus]->channels[i].effect_instances[j] = fx; + buses.write[p_bus]->channels.write[i].effect_instances.write[j] = fx; } } } @@ -841,7 +861,7 @@ void AudioServer::swap_bus_effects(int p_bus, int p_effect, int p_by_effect) { MARK_EDITED lock(); - SWAP(buses[p_bus]->effects[p_effect], buses[p_bus]->effects[p_by_effect]); + SWAP(buses.write[p_bus]->effects.write[p_effect], buses.write[p_bus]->effects.write[p_by_effect]); _update_bus_effects(p_bus); unlock(); } @@ -853,7 +873,7 @@ void AudioServer::set_bus_effect_enabled(int p_bus, int p_effect, bool p_enabled MARK_EDITED - buses[p_bus]->effects[p_effect].enabled = p_enabled; + buses.write[p_bus]->effects.write[p_effect].enabled = p_enabled; } bool AudioServer::is_bus_effect_enabled(int p_bus, int p_effect) const { @@ -890,13 +910,13 @@ void AudioServer::init_channels_and_buffers() { temp_buffer.resize(channel_count); for (int i = 0; i < temp_buffer.size(); i++) { - temp_buffer[i].resize(buffer_size); + temp_buffer.write[i].resize(buffer_size); } for (int i = 0; i < buses.size(); i++) { buses[i]->channels.resize(channel_count); for (int j = 0; j < channel_count; j++) { - buses[i]->channels[j].buffer.resize(buffer_size); + buses.write[i]->channels.write[j].buffer.resize(buffer_size); } } } @@ -976,7 +996,7 @@ void AudioServer::update() { if (!bus->effects[j].enabled) continue; - bus->effects[j].prof_time = 0; + bus->effects.write[j].prof_time = 0; } } @@ -1146,11 +1166,11 @@ void AudioServer::set_bus_layout(const Ref<AudioBusLayout> &p_bus_layout) { } bus_map[bus->name] = bus; - buses[i] = bus; + buses.write[i] = bus; buses[i]->channels.resize(channel_count); for (int j = 0; j < channel_count; j++) { - buses[i]->channels[j].buffer.resize(buffer_size); + buses.write[i]->channels.write[j].buffer.resize(buffer_size); } _update_bus_effects(i); } @@ -1169,17 +1189,17 @@ Ref<AudioBusLayout> AudioServer::generate_bus_layout() const { for (int i = 0; i < buses.size(); i++) { - state->buses[i].name = buses[i]->name; - state->buses[i].send = buses[i]->send; - state->buses[i].mute = buses[i]->mute; - state->buses[i].solo = buses[i]->solo; - state->buses[i].bypass = buses[i]->bypass; - state->buses[i].volume_db = buses[i]->volume_db; + state->buses.write[i].name = buses[i]->name; + state->buses.write[i].send = buses[i]->send; + state->buses.write[i].mute = buses[i]->mute; + state->buses.write[i].solo = buses[i]->solo; + state->buses.write[i].bypass = buses[i]->bypass; + state->buses.write[i].volume_db = buses[i]->volume_db; for (int j = 0; j < buses[i]->effects.size(); j++) { AudioBusLayout::Bus::Effect fx; fx.effect = buses[i]->effects[j].effect; fx.enabled = buses[i]->effects[j].enabled; - state->buses[i].effects.push_back(fx); + state->buses.write[i].effects.push_back(fx); } } @@ -1201,6 +1221,21 @@ void AudioServer::set_device(String device) { AudioDriver::get_singleton()->set_device(device); } +Array AudioServer::capture_get_device_list() { + + return AudioDriver::get_singleton()->capture_get_device_list(); +} + +String AudioServer::capture_get_device() { + + return AudioDriver::get_singleton()->capture_get_device(); +} + +void AudioServer::capture_set_device(const String &p_name) { + + AudioDriver::get_singleton()->capture_set_device(p_name); +} + void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("set_bus_count", "amount"), &AudioServer::set_bus_count); @@ -1251,6 +1286,10 @@ void AudioServer::_bind_methods() { ClassDB::bind_method(D_METHOD("get_device"), &AudioServer::get_device); ClassDB::bind_method(D_METHOD("set_device"), &AudioServer::set_device); + 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"), &AudioServer::capture_set_device); + ClassDB::bind_method(D_METHOD("set_bus_layout", "bus_layout"), &AudioServer::set_bus_layout); ClassDB::bind_method(D_METHOD("generate_bus_layout"), &AudioServer::generate_bus_layout); @@ -1294,7 +1333,7 @@ bool AudioBusLayout::_set(const StringName &p_name, const Variant &p_value) { buses.resize(index + 1); } - Bus &bus = buses[index]; + Bus &bus = buses.write[index]; String what = s.get_slice("/", 2); @@ -1316,7 +1355,7 @@ bool AudioBusLayout::_set(const StringName &p_name, const Variant &p_value) { bus.effects.resize(which + 1); } - Bus::Effect &fx = bus.effects[which]; + Bus::Effect &fx = bus.effects.write[which]; String fxwhat = s.get_slice("/", 4); if (fxwhat == "effect") { @@ -1410,5 +1449,5 @@ void AudioBusLayout::_get_property_list(List<PropertyInfo> *p_list) const { AudioBusLayout::AudioBusLayout() { buses.resize(1); - buses[0].name = "Master"; + buses.write[0].name = "Master"; } diff --git a/servers/audio_server.h b/servers/audio_server.h index 258fd1d9b0..2663a0f968 100644 --- a/servers/audio_server.h +++ b/servers/audio_server.h @@ -38,6 +38,8 @@ #include "variant.h" class AudioDriverDummy; +class AudioStream; +class AudioStreamSample; class AudioDriver { @@ -51,8 +53,13 @@ class AudioDriver { #endif protected: + Vector<int32_t> input_buffer; + unsigned int input_position; + unsigned int input_size; + void audio_server_process(int p_frames, int32_t *p_buffer, bool p_update_mix_time = true); void update_mix_time(int p_frames); + void input_buffer_write(int32_t sample); #ifdef DEBUG_ENABLED _FORCE_INLINE_ void start_counting_ticks() { prof_ticks = OS::get_singleton()->get_ticks_usec(); } @@ -91,11 +98,21 @@ public: virtual void unlock() = 0; virtual void finish() = 0; + virtual Error capture_start() { return FAILED; } + virtual Error capture_stop() { return FAILED; } + virtual void capture_set_device(const String &p_name) {} + virtual String capture_get_device() { return "Default"; } + virtual Array capture_get_device_list(); // TODO: convert this and get_device_list to PoolStringArray + virtual float get_latency() { return 0; } SpeakerMode get_speaker_mode_by_total_channels(int p_channels) const; int get_total_channels_by_speaker_mode(SpeakerMode) const; + Vector<int32_t> get_input_buffer() { return input_buffer; } + unsigned int get_input_position() { return input_position; } + unsigned int get_input_size() { return input_size; } + #ifdef DEBUG_ENABLED uint64_t get_profiling_time() const { return prof_time; } void reset_profiling_time() { prof_time = 0; } @@ -222,6 +239,18 @@ private: void _mix_step(); +#if 0 + struct AudioInBlock { + + Ref<AudioStreamSample> audio_stream; + int current_position; + bool loops; + }; + + Map<StringName, AudioInBlock *> audio_in_block_map; + Vector<AudioInBlock *> audio_in_blocks; +#endif + struct CallbackItem { AudioCallback callback; @@ -335,8 +364,11 @@ public: String get_device(); void set_device(String device); - float get_output_latency() { return output_latency; } + Array capture_get_device_list(); + 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_pair_sw.cpp b/servers/physics/body_pair_sw.cpp index 2a6a9e08ae..0ce38e4486 100644 --- a/servers/physics/body_pair_sw.cpp +++ b/servers/physics/body_pair_sw.cpp @@ -211,6 +211,14 @@ bool BodyPairSW::_test_ccd(real_t p_step, BodySW *p_A, int p_shape_A, const Tran return true; } +real_t combine_bounce(BodySW *A, BodySW *B) { + return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1); +} + +real_t combine_friction(BodySW *A, BodySW *B) { + return ABS(MIN(A->get_friction(), B->get_friction())); +} + bool BodyPairSW::setup(real_t p_step) { //cannot collide @@ -331,7 +339,7 @@ bool BodyPairSW::setup(real_t p_step) { c.acc_bias_impulse = 0; c.acc_bias_impulse_center_of_mass = 0; - c.bounce = MAX(A->get_bounce(), B->get_bounce()); + c.bounce = combine_bounce(A, B); if (c.bounce) { Vector3 crA = A->get_angular_velocity().cross(c.rA); @@ -421,7 +429,7 @@ void BodyPairSW::solve(real_t p_step) { //friction impulse - real_t friction = A->get_friction() * B->get_friction(); + real_t friction = combine_friction(A, B); Vector3 lvA = A->get_linear_velocity() + A->get_angular_velocity().cross(c.rA); Vector3 lvB = B->get_linear_velocity() + B->get_angular_velocity().cross(c.rB); diff --git a/servers/physics/body_sw.h b/servers/physics/body_sw.h index fd2ab16b84..9d7b147fd6 100644 --- a/servers/physics/body_sw.h +++ b/servers/physics/body_sw.h @@ -157,7 +157,7 @@ public: _FORCE_INLINE_ void add_area(AreaSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { - areas[index].refCount += 1; + areas.write[index].refCount += 1; } else { areas.ordered_insert(AreaCMP(p_area)); } @@ -166,7 +166,7 @@ public: _FORCE_INLINE_ void remove_area(AreaSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { - areas[index].refCount -= 1; + areas.write[index].refCount -= 1; if (areas[index].refCount < 1) areas.remove(index); } @@ -217,6 +217,10 @@ public: _FORCE_INLINE_ const Vector3 &get_biased_linear_velocity() const { return biased_linear_velocity; } _FORCE_INLINE_ const Vector3 &get_biased_angular_velocity() const { return biased_angular_velocity; } + _FORCE_INLINE_ void apply_central_impulse(const Vector3 &p_j) { + linear_velocity += p_j * _inv_mass; + } + _FORCE_INLINE_ void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { linear_velocity += p_j * _inv_mass; @@ -344,7 +348,7 @@ void BodySW::add_contact(const Vector3 &p_local_pos, const Vector3 &p_local_norm if (c_max == 0) return; - Contact *c = &contacts[0]; + Contact *c = contacts.ptrw(); int idx = -1; @@ -413,6 +417,7 @@ public: virtual void add_central_force(const Vector3 &p_force) { body->add_central_force(p_force); } virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) { body->add_force(p_force, p_pos); } virtual void add_torque(const Vector3 &p_torque) { body->add_torque(p_torque); } + virtual void apply_central_impulse(const Vector3 &p_j) { body->apply_central_impulse(p_j); } virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) { body->apply_impulse(p_pos, p_j); } virtual void apply_torque_impulse(const Vector3 &p_j) { body->apply_torque_impulse(p_j); } @@ -429,6 +434,9 @@ public: ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, Vector3()); return body->contacts[p_contact_idx].local_normal; } + virtual float get_contact_impulse(int p_contact_idx) const { + return 0.0f; // Only implemented for bullet + } virtual int get_contact_local_shape(int p_contact_idx) const { ERR_FAIL_INDEX_V(p_contact_idx, body->contact_count, -1); return body->contacts[p_contact_idx].local_shape; diff --git a/servers/physics/collision_object_sw.cpp b/servers/physics/collision_object_sw.cpp index f7a58a9cf2..09f72ff39b 100644 --- a/servers/physics/collision_object_sw.cpp +++ b/servers/physics/collision_object_sw.cpp @@ -53,7 +53,7 @@ void CollisionObjectSW::set_shape(int p_index, ShapeSW *p_shape) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes[p_index].shape->remove_owner(this); - shapes[p_index].shape = p_shape; + shapes.write[p_index].shape = p_shape; p_shape->add_owner(this); if (!pending_shape_update_list.in_list()) { @@ -66,8 +66,8 @@ void CollisionObjectSW::set_shape_transform(int p_index, const Transform &p_tran ERR_FAIL_INDEX(p_index, shapes.size()); - shapes[p_index].xform = p_transform; - shapes[p_index].xform_inv = p_transform.affine_inverse(); + shapes.write[p_index].xform = p_transform; + shapes.write[p_index].xform_inv = p_transform.affine_inverse(); if (!pending_shape_update_list.in_list()) { PhysicsServerSW::singleton->pending_shape_update_list.add(&pending_shape_update_list); } @@ -97,7 +97,7 @@ void CollisionObjectSW::remove_shape(int p_index) { continue; //should never get here with a null owner space->get_broadphase()->remove(shapes[i].bpid); - shapes[i].bpid = 0; + shapes.write[i].bpid = 0; } shapes[p_index].shape->remove_owner(this); shapes.remove(p_index); @@ -117,7 +117,7 @@ void CollisionObjectSW::_set_static(bool p_static) { if (!space) return; for (int i = 0; i < get_shape_count(); i++) { - Shape &s = shapes[i]; + const Shape &s = shapes[i]; if (s.bpid > 0) { space->get_broadphase()->set_static(s.bpid, _static); } @@ -128,7 +128,7 @@ void CollisionObjectSW::_unregister_shapes() { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid > 0) { space->get_broadphase()->remove(s.bpid); s.bpid = 0; @@ -143,7 +143,7 @@ void CollisionObjectSW::_update_shapes() { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid == 0) { s.bpid = space->get_broadphase()->create(this, i); space->get_broadphase()->set_static(s.bpid, _static); @@ -170,7 +170,7 @@ void CollisionObjectSW::_update_shapes_with_motion(const Vector3 &p_motion) { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid == 0) { s.bpid = space->get_broadphase()->create(this, i); space->get_broadphase()->set_static(s.bpid, _static); @@ -195,7 +195,7 @@ void CollisionObjectSW::_set_space(SpaceSW *p_space) { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid) { space->get_broadphase()->remove(s.bpid); s.bpid = 0; diff --git a/servers/physics/collision_object_sw.h b/servers/physics/collision_object_sw.h index dee28bb6df..b6430b38dc 100644 --- a/servers/physics/collision_object_sw.h +++ b/servers/physics/collision_object_sw.h @@ -135,7 +135,7 @@ public: _FORCE_INLINE_ void set_ray_pickable(bool p_enable) { ray_pickable = p_enable; } _FORCE_INLINE_ bool is_ray_pickable() const { return ray_pickable; } - _FORCE_INLINE_ void set_shape_as_disabled(int p_idx, bool p_enable) { shapes[p_idx].disabled = p_enable; } + _FORCE_INLINE_ void set_shape_as_disabled(int p_idx, bool p_enable) { shapes.write[p_idx].disabled = p_enable; } _FORCE_INLINE_ bool is_shape_set_as_disabled(int p_idx) const { return shapes[p_idx].disabled; } _FORCE_INLINE_ void set_collision_layer(uint32_t p_layer) { collision_layer = p_layer; } diff --git a/servers/physics/collision_solver_sat.cpp b/servers/physics/collision_solver_sat.cpp index e587485fcb..b059c20c95 100644 --- a/servers/physics/collision_solver_sat.cpp +++ b/servers/physics/collision_solver_sat.cpp @@ -217,8 +217,6 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_ // generate contacts //Plane plane_A(p_points_A[0],p_points_A[1],p_points_A[2]); - int added = 0; - for (int i = 0; i < clipbuf_len; i++) { real_t d = plane_B.distance_to(clipbuf_src[i]); @@ -233,7 +231,6 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_ continue; p_callback->call(clipbuf_src[i], closest_B); - added++; } } @@ -351,7 +348,9 @@ public: //use the smallest depth - min_B = -min_B; + if (min_B < 0.0) { // could be +0.0, we don't want it to become -0.0 + min_B = -min_B; + } if (max_B < min_B) { if (max_B < best_depth) { @@ -561,6 +560,12 @@ static void _collision_sphere_capsule(const ShapeSW *p_a, const Transform &p_tra } template <bool withMargin> +static void _collision_sphere_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> static void _collision_sphere_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const SphereShapeSW *sphere_A = static_cast<const SphereShapeSW *>(p_a); @@ -852,6 +857,12 @@ static void _collision_box_capsule(const ShapeSW *p_a, const Transform &p_transf } template <bool withMargin> +static void _collision_box_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> static void _collision_box_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const BoxShapeSW *box_A = static_cast<const BoxShapeSW *>(p_a); @@ -1128,6 +1139,12 @@ static void _collision_capsule_capsule(const ShapeSW *p_a, const Transform &p_tr } template <bool withMargin> +static void _collision_capsule_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> static void _collision_capsule_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const CapsuleShapeSW *capsule_A = static_cast<const CapsuleShapeSW *>(p_a); @@ -1248,6 +1265,24 @@ static void _collision_capsule_face(const ShapeSW *p_a, const Transform &p_trans } template <bool withMargin> +static void _collision_cylinder_cylinder(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> +static void _collision_cylinder_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> +static void _collision_cylinder_face(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { + + return; +} + +template <bool withMargin> static void _collision_convex_polygon_convex_polygon(const ShapeSW *p_a, const Transform &p_transform_a, const ShapeSW *p_b, const Transform &p_transform_b, _CollectorCallback *p_collector, real_t p_margin_a, real_t p_margin_b) { const ConvexPolygonShapeSW *convex_polygon_A = static_cast<const ConvexPolygonShapeSW *>(p_a); @@ -1476,59 +1511,81 @@ bool sat_calculate_penetration(const ShapeSW *p_shape_A, const Transform &p_tran ERR_FAIL_COND_V(type_B == PhysicsServer::SHAPE_RAY, false); ERR_FAIL_COND_V(p_shape_B->is_concave(), false); - static const CollisionFunc collision_table[5][5] = { + static const CollisionFunc collision_table[6][6] = { { _collision_sphere_sphere<false>, _collision_sphere_box<false>, _collision_sphere_capsule<false>, + _collision_sphere_cylinder<false>, _collision_sphere_convex_polygon<false>, _collision_sphere_face<false> }, { 0, _collision_box_box<false>, _collision_box_capsule<false>, + _collision_box_cylinder<false>, _collision_box_convex_polygon<false>, _collision_box_face<false> }, { 0, 0, _collision_capsule_capsule<false>, + _collision_capsule_cylinder<false>, _collision_capsule_convex_polygon<false>, _collision_capsule_face<false> }, { 0, 0, 0, + _collision_cylinder_cylinder<false>, + _collision_cylinder_convex_polygon<false>, + _collision_cylinder_face<false> }, + { 0, + 0, + 0, + 0, _collision_convex_polygon_convex_polygon<false>, _collision_convex_polygon_face<false> }, { 0, 0, 0, 0, + 0, 0 }, }; - static const CollisionFunc collision_table_margin[5][5] = { + static const CollisionFunc collision_table_margin[6][6] = { { _collision_sphere_sphere<true>, _collision_sphere_box<true>, _collision_sphere_capsule<true>, + _collision_sphere_cylinder<true>, _collision_sphere_convex_polygon<true>, _collision_sphere_face<true> }, { 0, _collision_box_box<true>, _collision_box_capsule<true>, + _collision_box_cylinder<true>, _collision_box_convex_polygon<true>, _collision_box_face<true> }, { 0, 0, _collision_capsule_capsule<true>, + _collision_capsule_cylinder<true>, _collision_capsule_convex_polygon<true>, _collision_capsule_face<true> }, { 0, 0, 0, + _collision_cylinder_cylinder<true>, + _collision_cylinder_convex_polygon<true>, + _collision_cylinder_face<true> }, + { 0, + 0, + 0, + 0, _collision_convex_polygon_convex_polygon<true>, _collision_convex_polygon_face<true> }, { 0, 0, 0, 0, + 0, 0 }, }; diff --git a/servers/physics/physics_server_sw.cpp b/servers/physics/physics_server_sw.cpp index 593218dd5d..3a32c46a9b 100644 --- a/servers/physics/physics_server_sw.cpp +++ b/servers/physics/physics_server_sw.cpp @@ -763,6 +763,40 @@ Vector3 PhysicsServerSW::body_get_applied_torque(RID p_body) const { return body->get_applied_torque(); }; +void PhysicsServerSW::body_add_central_force(RID p_body, const Vector3 &p_force) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_central_force(p_force); + body->wakeup(); +} + +void PhysicsServerSW::body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_force(p_force, p_pos); + body->wakeup(); +}; + +void PhysicsServerSW::body_add_torque(RID p_body, const Vector3 &p_torque) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_torque(p_torque); + body->wakeup(); +}; + +void PhysicsServerSW::body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) { + BodySW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + _update_shapes(); + + body->apply_central_impulse(p_impulse); + body->wakeup(); +} + void PhysicsServerSW::body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) { BodySW *body = body_owner.get(p_body); diff --git a/servers/physics/physics_server_sw.h b/servers/physics/physics_server_sw.h index 3f56ba26d0..1c5754124d 100644 --- a/servers/physics/physics_server_sw.h +++ b/servers/physics/physics_server_sw.h @@ -200,6 +200,11 @@ public: virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque); virtual Vector3 body_get_applied_torque(RID p_body) const; + virtual void body_add_central_force(RID p_body, const Vector3 &p_force); + virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos); + virtual void body_add_torque(RID p_body, const Vector3 &p_torque); + + virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse); virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse); virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity); @@ -230,6 +235,72 @@ public: // this function only works on physics process, errors and returns null otherwise virtual PhysicsDirectBodyState *body_get_direct_state(RID p_body); + /* SOFT BODY */ + + virtual RID soft_body_create(bool p_init_sleeping = false) { return RID(); } + + virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) {} + + virtual void soft_body_set_space(RID p_body, RID p_space) {} + virtual RID soft_body_get_space(RID p_body) const { return RID(); } + + virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) {} + virtual uint32_t soft_body_get_collision_layer(RID p_body) const { return 0; } + + virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) {} + virtual uint32_t soft_body_get_collision_mask(RID p_body) const { return 0; } + + virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) {} + virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) {} + virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) {} + + virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) {} + virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const { return Variant(); } + + virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) {} + virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const { return Vector3(); } + + virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) {} + virtual bool soft_body_is_ray_pickable(RID p_body) const { return false; } + + virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) {} + virtual int soft_body_get_simulation_precision(RID p_body) { return 0; } + + virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) {} + virtual real_t soft_body_get_total_mass(RID p_body) { return 0.; } + + virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) {} + virtual real_t soft_body_get_linear_stiffness(RID p_body) { return 0.; } + + virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) {} + virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) { return 0.; } + + virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) {} + virtual real_t soft_body_get_volume_stiffness(RID p_body) { return 0.; } + + virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) {} + virtual real_t soft_body_get_pressure_coefficient(RID p_body) { return 0.; } + + virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) {} + virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) { return 0.; } + + virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) {} + virtual real_t soft_body_get_damping_coefficient(RID p_body) { return 0.; } + + virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) {} + virtual real_t soft_body_get_drag_coefficient(RID p_body) { return 0.; } + + virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) {} + + virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) {} + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) { return Vector3(); } + + virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const { return Vector3(); } + + virtual void soft_body_remove_all_pinned_points(RID p_body) {} + virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) {} + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) { return 0; } + /* JOINT API */ virtual RID joint_create_pin(RID p_body_A, const Vector3 &p_local_A, RID p_body_B, const Vector3 &p_local_B); diff --git a/servers/physics/space_sw.h b/servers/physics/space_sw.h index 2452d6a187..4d864e9a51 100644 --- a/servers/physics/space_sw.h +++ b/servers/physics/space_sw.h @@ -186,7 +186,7 @@ public: void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } _FORCE_INLINE_ void add_debug_contact(const Vector3 &p_contact) { - if (contact_debug_count < contact_debug.size()) contact_debug[contact_debug_count++] = p_contact; + if (contact_debug_count < contact_debug.size()) contact_debug.write[contact_debug_count++] = p_contact; } _FORCE_INLINE_ Vector<Vector3> get_debug_contacts() { return contact_debug; } _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; } diff --git a/servers/physics_2d/body_2d_sw.h b/servers/physics_2d/body_2d_sw.h index 782adf3416..69184ad484 100644 --- a/servers/physics_2d/body_2d_sw.h +++ b/servers/physics_2d/body_2d_sw.h @@ -139,7 +139,7 @@ public: _FORCE_INLINE_ void add_area(Area2DSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { - areas[index].refCount += 1; + areas.write[index].refCount += 1; } else { areas.ordered_insert(AreaCMP(p_area)); } @@ -148,7 +148,7 @@ public: _FORCE_INLINE_ void remove_area(Area2DSW *p_area) { int index = areas.find(AreaCMP(p_area)); if (index > -1) { - areas[index].refCount -= 1; + areas.write[index].refCount -= 1; if (areas[index].refCount < 1) areas.remove(index); } @@ -199,12 +199,20 @@ public: _FORCE_INLINE_ void set_biased_angular_velocity(real_t p_velocity) { biased_angular_velocity = p_velocity; } _FORCE_INLINE_ real_t get_biased_angular_velocity() const { return biased_angular_velocity; } + _FORCE_INLINE_ void apply_central_impulse(const Vector2 &p_impulse) { + linear_velocity += p_impulse * _inv_mass; + } + _FORCE_INLINE_ void apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) { linear_velocity += p_impulse * _inv_mass; angular_velocity += _inv_inertia * p_offset.cross(p_impulse); } + _FORCE_INLINE_ void apply_torque_impulse(real_t p_torque) { + angular_velocity += _inv_inertia * p_torque; + } + _FORCE_INLINE_ void apply_bias_impulse(const Vector2 &p_pos, const Vector2 &p_j) { biased_linear_velocity += p_j * _inv_mass; @@ -235,12 +243,20 @@ public: void set_applied_torque(real_t p_torque) { applied_torque = p_torque; } real_t get_applied_torque() const { return applied_torque; } - _FORCE_INLINE_ void add_force(const Vector2 &p_force, const Vector2 &p_offset) { + _FORCE_INLINE_ void add_central_force(const Vector2 &p_force) { + applied_force += p_force; + } + + _FORCE_INLINE_ void add_force(const Vector2 &p_offset, const Vector2 &p_force) { applied_force += p_force; applied_torque += p_offset.cross(p_force); } + _FORCE_INLINE_ void add_torque(real_t p_torque) { + applied_torque += p_torque; + } + _FORCE_INLINE_ void set_continuous_collision_detection_mode(Physics2DServer::CCDMode p_mode) { continuous_cd_mode = p_mode; } _FORCE_INLINE_ Physics2DServer::CCDMode get_continuous_collision_detection_mode() const { return continuous_cd_mode; } @@ -287,7 +303,7 @@ void Body2DSW::add_contact(const Vector2 &p_local_pos, const Vector2 &p_local_no if (c_max == 0) return; - Contact *c = &contacts[0]; + Contact *c = contacts.ptrw(); int idx = -1; @@ -349,6 +365,13 @@ public: virtual void set_transform(const Transform2D &p_transform) { body->set_state(Physics2DServer::BODY_STATE_TRANSFORM, p_transform); } virtual Transform2D get_transform() const { return body->get_transform(); } + virtual void add_central_force(const Vector2 &p_force) { body->add_central_force(p_force); } + virtual void add_force(const Vector2 &p_offset, const Vector2 &p_force) { body->add_force(p_offset, p_force); } + virtual void add_torque(real_t p_torque) { body->add_torque(p_torque); } + virtual void apply_central_impulse(const Vector2 &p_impulse) { body->apply_central_impulse(p_impulse); } + virtual void apply_impulse(const Vector2 &p_offset, const Vector2 &p_force) { body->apply_impulse(p_offset, p_force); } + virtual void apply_torque_impulse(real_t p_torque) { body->apply_torque_impulse(p_torque); } + virtual void set_sleep_state(bool p_enable) { body->set_active(!p_enable); } virtual bool is_sleeping() const { return !body->is_active(); } diff --git a/servers/physics_2d/body_pair_2d_sw.cpp b/servers/physics_2d/body_pair_2d_sw.cpp index 61c0e0063f..2633edf7bb 100644 --- a/servers/physics_2d/body_pair_2d_sw.cpp +++ b/servers/physics_2d/body_pair_2d_sw.cpp @@ -219,6 +219,14 @@ bool BodyPair2DSW::_test_ccd(real_t p_step, Body2DSW *p_A, int p_shape_A, const return true; } +real_t combine_bounce(Body2DSW *A, Body2DSW *B) { + return CLAMP(A->get_bounce() + B->get_bounce(), 0, 1); +} + +real_t combine_friction(Body2DSW *A, Body2DSW *B) { + return ABS(MIN(A->get_friction(), B->get_friction())); +} + bool BodyPair2DSW::setup(real_t p_step) { //cannot collide @@ -432,7 +440,7 @@ bool BodyPair2DSW::setup(real_t p_step) { #endif - c.bounce = MAX(A->get_bounce(), B->get_bounce()); + c.bounce = combine_bounce(A, B); if (c.bounce) { Vector2 crA(-A->get_angular_velocity() * c.rA.y, A->get_angular_velocity() * c.rA.x); @@ -488,7 +496,7 @@ void BodyPair2DSW::solve(real_t p_step) { real_t jnOld = c.acc_normal_impulse; c.acc_normal_impulse = MAX(jnOld + jn, 0.0f); - real_t friction = A->get_friction() * B->get_friction(); + real_t friction = combine_friction(A, B); real_t jtMax = friction * c.acc_normal_impulse; real_t jt = -vt * c.mass_tangent; diff --git a/servers/physics_2d/collision_object_2d_sw.cpp b/servers/physics_2d/collision_object_2d_sw.cpp index 23084a4241..4dd5b2040f 100644 --- a/servers/physics_2d/collision_object_2d_sw.cpp +++ b/servers/physics_2d/collision_object_2d_sw.cpp @@ -50,7 +50,7 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { ERR_FAIL_INDEX(p_index, shapes.size()); shapes[p_index].shape->remove_owner(this); - shapes[p_index].shape = p_shape; + shapes.write[p_index].shape = p_shape; p_shape->add_owner(this); _update_shapes(); @@ -60,15 +60,15 @@ void CollisionObject2DSW::set_shape(int p_index, Shape2DSW *p_shape) { void CollisionObject2DSW::set_shape_metadata(int p_index, const Variant &p_metadata) { ERR_FAIL_INDEX(p_index, shapes.size()); - shapes[p_index].metadata = p_metadata; + shapes.write[p_index].metadata = p_metadata; } void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_transform) { ERR_FAIL_INDEX(p_index, shapes.size()); - shapes[p_index].xform = p_transform; - shapes[p_index].xform_inv = p_transform.affine_inverse(); + shapes.write[p_index].xform = p_transform; + shapes.write[p_index].xform_inv = p_transform.affine_inverse(); _update_shapes(); _shapes_changed(); } @@ -76,7 +76,7 @@ void CollisionObject2DSW::set_shape_transform(int p_index, const Transform2D &p_ void CollisionObject2DSW::set_shape_as_disabled(int p_idx, bool p_disabled) { ERR_FAIL_INDEX(p_idx, shapes.size()); - CollisionObject2DSW::Shape &shape = shapes[p_idx]; + CollisionObject2DSW::Shape &shape = shapes.write[p_idx]; if (shape.disabled == p_disabled) return; @@ -116,7 +116,7 @@ void CollisionObject2DSW::remove_shape(int p_index) { continue; //should never get here with a null owner space->get_broadphase()->remove(shapes[i].bpid); - shapes[i].bpid = 0; + shapes.write[i].bpid = 0; } shapes[p_index].shape->remove_owner(this); shapes.remove(p_index); @@ -133,7 +133,7 @@ void CollisionObject2DSW::_set_static(bool p_static) { if (!space) return; for (int i = 0; i < get_shape_count(); i++) { - Shape &s = shapes[i]; + const Shape &s = shapes[i]; if (s.bpid > 0) { space->get_broadphase()->set_static(s.bpid, _static); } @@ -144,7 +144,7 @@ void CollisionObject2DSW::_unregister_shapes() { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid > 0) { space->get_broadphase()->remove(s.bpid); s.bpid = 0; @@ -159,7 +159,7 @@ void CollisionObject2DSW::_update_shapes() { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.disabled) continue; @@ -187,7 +187,7 @@ void CollisionObject2DSW::_update_shapes_with_motion(const Vector2 &p_motion) { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.disabled) continue; @@ -215,7 +215,7 @@ void CollisionObject2DSW::_set_space(Space2DSW *p_space) { for (int i = 0; i < shapes.size(); i++) { - Shape &s = shapes[i]; + Shape &s = shapes.write[i]; if (s.bpid) { space->get_broadphase()->remove(s.bpid); s.bpid = 0; diff --git a/servers/physics_2d/collision_object_2d_sw.h b/servers/physics_2d/collision_object_2d_sw.h index ab3e219ac0..393c4a6ed7 100644 --- a/servers/physics_2d/collision_object_2d_sw.h +++ b/servers/physics_2d/collision_object_2d_sw.h @@ -144,7 +144,7 @@ public: _FORCE_INLINE_ void set_shape_as_one_way_collision(int p_idx, bool p_one_way_collision) { ERR_FAIL_INDEX(p_idx, shapes.size()); - shapes[p_idx].one_way_collision = p_one_way_collision; + shapes.write[p_idx].one_way_collision = p_one_way_collision; } _FORCE_INLINE_ bool is_shape_set_as_one_way_collision(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, shapes.size(), false); diff --git a/servers/physics_2d/physics_2d_server_sw.cpp b/servers/physics_2d/physics_2d_server_sw.cpp index a473e0beb2..15e80bcd5e 100644 --- a/servers/physics_2d/physics_2d_server_sw.cpp +++ b/servers/physics_2d/physics_2d_server_sw.cpp @@ -838,6 +838,21 @@ real_t Physics2DServerSW::body_get_applied_torque(RID p_body) const { return body->get_applied_torque(); }; +void Physics2DServerSW::body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) { + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_central_impulse(p_impulse); + body->wakeup(); +} + +void Physics2DServerSW::body_apply_torque_impulse(RID p_body, real_t p_torque) { + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->apply_torque_impulse(p_torque); +} + void Physics2DServerSW::body_apply_impulse(RID p_body, const Vector2 &p_pos, const Vector2 &p_impulse) { Body2DSW *body = body_owner.get(p_body); @@ -847,12 +862,28 @@ void Physics2DServerSW::body_apply_impulse(RID p_body, const Vector2 &p_pos, con body->wakeup(); }; +void Physics2DServerSW::body_add_central_force(RID p_body, const Vector2 &p_force) { + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_central_force(p_force); + body->wakeup(); +}; + void Physics2DServerSW::body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force) { Body2DSW *body = body_owner.get(p_body); ERR_FAIL_COND(!body); - body->add_force(p_force, p_offset); + body->add_force(p_offset, p_force); + body->wakeup(); +}; + +void Physics2DServerSW::body_add_torque(RID p_body, real_t p_torque) { + Body2DSW *body = body_owner.get(p_body); + ERR_FAIL_COND(!body); + + body->add_torque(p_torque); body->wakeup(); }; diff --git a/servers/physics_2d/physics_2d_server_sw.h b/servers/physics_2d/physics_2d_server_sw.h index e5961b9011..d4fc44b1d7 100644 --- a/servers/physics_2d/physics_2d_server_sw.h +++ b/servers/physics_2d/physics_2d_server_sw.h @@ -209,8 +209,12 @@ public: virtual void body_set_applied_torque(RID p_body, real_t p_torque); virtual real_t body_get_applied_torque(RID p_body) const; + virtual void body_add_central_force(RID p_body, const Vector2 &p_force); virtual void body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force); + virtual void body_add_torque(RID p_body, real_t p_torque); + virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse); + virtual void body_apply_torque_impulse(RID p_body, real_t p_torque); virtual void body_apply_impulse(RID p_body, const Vector2 &p_pos, const Vector2 &p_impulse); virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity); diff --git a/servers/physics_2d/physics_2d_server_wrap_mt.h b/servers/physics_2d/physics_2d_server_wrap_mt.h index 3119b930d7..6b34fb9739 100644 --- a/servers/physics_2d/physics_2d_server_wrap_mt.h +++ b/servers/physics_2d/physics_2d_server_wrap_mt.h @@ -220,7 +220,11 @@ public: FUNC2(body_set_applied_torque, RID, real_t); FUNC1RC(real_t, body_get_applied_torque, RID); + FUNC2(body_add_central_force, RID, const Vector2 &); FUNC3(body_add_force, RID, const Vector2 &, const Vector2 &); + FUNC2(body_add_torque, RID, real_t); + FUNC2(body_apply_central_impulse, RID, const Vector2 &); + FUNC2(body_apply_torque_impulse, RID, real_t); FUNC3(body_apply_impulse, RID, const Vector2 &, const Vector2 &); FUNC2(body_set_axis_velocity, RID, const Vector2 &); diff --git a/servers/physics_2d/shape_2d_sw.cpp b/servers/physics_2d/shape_2d_sw.cpp index 2b0eab5999..dc8ec23e69 100644 --- a/servers/physics_2d/shape_2d_sw.cpp +++ b/servers/physics_2d/shape_2d_sw.cpp @@ -891,8 +891,8 @@ int ConcavePolygonShape2DSW::_generate_bvh(BVH *p_bvh, int p_len, int p_depth) { int l = _generate_bvh(p_bvh, median, p_depth + 1); int r = _generate_bvh(&p_bvh[median], p_len - median, p_depth + 1); - bvh[node_idx].left = l; - bvh[node_idx].right = r; + bvh.write[node_idx].left = l; + bvh.write[node_idx].right = r; return node_idx; } @@ -953,20 +953,20 @@ void ConcavePolygonShape2DSW::set_data(const Variant &p_data) { for (Map<Point2, int>::Element *E = pointmap.front(); E; E = E->next()) { aabb.expand_to(E->key()); - points[E->get()] = E->key(); + points.write[E->get()] = E->key(); } Vector<BVH> main_vbh; main_vbh.resize(segments.size()); for (int i = 0; i < main_vbh.size(); i++) { - main_vbh[i].aabb.position = points[segments[i].points[0]]; - main_vbh[i].aabb.expand_to(points[segments[i].points[1]]); - main_vbh[i].left = -1; - main_vbh[i].right = i; + main_vbh.write[i].aabb.position = points[segments[i].points[0]]; + main_vbh.write[i].aabb.expand_to(points[segments[i].points[1]]); + main_vbh.write[i].left = -1; + main_vbh.write[i].right = i; } - _generate_bvh(&main_vbh[0], main_vbh.size(), 1); + _generate_bvh(main_vbh.ptrw(), main_vbh.size(), 1); } else { //dictionary with arrays diff --git a/servers/physics_2d/space_2d_sw.h b/servers/physics_2d/space_2d_sw.h index 959e15e12d..1247317b03 100644 --- a/servers/physics_2d/space_2d_sw.h +++ b/servers/physics_2d/space_2d_sw.h @@ -188,7 +188,7 @@ public: void set_debug_contacts(int p_amount) { contact_debug.resize(p_amount); } _FORCE_INLINE_ bool is_debugging_contacts() const { return !contact_debug.empty(); } _FORCE_INLINE_ void add_debug_contact(const Vector2 &p_contact) { - if (contact_debug_count < contact_debug.size()) contact_debug[contact_debug_count++] = p_contact; + if (contact_debug_count < contact_debug.size()) contact_debug.write[contact_debug_count++] = p_contact; } _FORCE_INLINE_ Vector<Vector2> get_debug_contacts() { return contact_debug; } _FORCE_INLINE_ int get_debug_contact_count() { return contact_debug_count; } diff --git a/servers/physics_2d_server.cpp b/servers/physics_2d_server.cpp index cb7669ec24..37c4bc83ad 100644 --- a/servers/physics_2d_server.cpp +++ b/servers/physics_2d_server.cpp @@ -91,6 +91,13 @@ void Physics2DDirectBodyState::_bind_methods() { ClassDB::bind_method(D_METHOD("set_transform", "transform"), &Physics2DDirectBodyState::set_transform); ClassDB::bind_method(D_METHOD("get_transform"), &Physics2DDirectBodyState::get_transform); + ClassDB::bind_method(D_METHOD("add_central_force", "force"), &Physics2DDirectBodyState::add_central_force); + ClassDB::bind_method(D_METHOD("add_force", "offset", "force"), &Physics2DDirectBodyState::add_force); + ClassDB::bind_method(D_METHOD("add_torque", "torque"), &Physics2DDirectBodyState::add_torque); + ClassDB::bind_method(D_METHOD("apply_central_impulse", "impulse"), &Physics2DDirectBodyState::apply_central_impulse); + ClassDB::bind_method(D_METHOD("apply_torque_impulse", "impulse"), &Physics2DDirectBodyState::apply_torque_impulse); + ClassDB::bind_method(D_METHOD("apply_impulse", "offset", "impulse"), &Physics2DDirectBodyState::apply_impulse); + ClassDB::bind_method(D_METHOD("set_sleep_state", "enabled"), &Physics2DDirectBodyState::set_sleep_state); ClassDB::bind_method(D_METHOD("is_sleeping"), &Physics2DDirectBodyState::is_sleeping); @@ -191,7 +198,7 @@ Vector<RID> Physics2DShapeQueryParameters::get_exclude() const { ret.resize(exclude.size()); int idx = 0; for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) { - ret[idx] = E->get(); + ret.write[idx] = E->get(); } return ret; } @@ -585,8 +592,12 @@ void Physics2DServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &Physics2DServer::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &Physics2DServer::body_get_state); + ClassDB::bind_method(D_METHOD("body_apply_central_impulse", "body", "impulse"), &Physics2DServer::body_apply_central_impulse); + ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &Physics2DServer::body_apply_torque_impulse); ClassDB::bind_method(D_METHOD("body_apply_impulse", "body", "position", "impulse"), &Physics2DServer::body_apply_impulse); + ClassDB::bind_method(D_METHOD("body_add_central_force", "body", "force"), &Physics2DServer::body_add_central_force); ClassDB::bind_method(D_METHOD("body_add_force", "body", "offset", "force"), &Physics2DServer::body_add_force); + ClassDB::bind_method(D_METHOD("body_add_torque", "body", "torque"), &Physics2DServer::body_add_torque); ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &Physics2DServer::body_set_axis_velocity); ClassDB::bind_method(D_METHOD("body_add_collision_exception", "body", "excepted_body"), &Physics2DServer::body_add_collision_exception); diff --git a/servers/physics_2d_server.h b/servers/physics_2d_server.h index 1d04fbc5c6..f42d9868f0 100644 --- a/servers/physics_2d_server.h +++ b/servers/physics_2d_server.h @@ -61,6 +61,13 @@ public: virtual void set_transform(const Transform2D &p_transform) = 0; virtual Transform2D get_transform() const = 0; + virtual void add_central_force(const Vector2 &p_force) = 0; + virtual void add_force(const Vector2 &p_offset, const Vector2 &p_force) = 0; + virtual void add_torque(real_t p_torque) = 0; + virtual void apply_central_impulse(const Vector2 &p_impulse) = 0; + virtual void apply_torque_impulse(real_t p_torque) = 0; + virtual void apply_impulse(const Vector2 &p_offset, const Vector2 &p_impulse) = 0; + virtual void set_sleep_state(bool p_enable) = 0; virtual bool is_sleeping() const = 0; @@ -435,8 +442,12 @@ public: virtual void body_set_applied_torque(RID p_body, float p_torque) = 0; virtual float body_get_applied_torque(RID p_body) const = 0; + virtual void body_add_central_force(RID p_body, const Vector2 &p_force) = 0; virtual void body_add_force(RID p_body, const Vector2 &p_offset, const Vector2 &p_force) = 0; + virtual void body_add_torque(RID p_body, float p_torque) = 0; + virtual void body_apply_central_impulse(RID p_body, const Vector2 &p_impulse) = 0; + virtual void body_apply_torque_impulse(RID p_body, float p_torque) = 0; virtual void body_apply_impulse(RID p_body, const Vector2 &p_offset, const Vector2 &p_impulse) = 0; virtual void body_set_axis_velocity(RID p_body, const Vector2 &p_axis_velocity) = 0; diff --git a/servers/physics_server.cpp b/servers/physics_server.cpp index b4bd4cb35f..cda3856ecc 100644 --- a/servers/physics_server.cpp +++ b/servers/physics_server.cpp @@ -95,6 +95,7 @@ void PhysicsDirectBodyState::_bind_methods() { ClassDB::bind_method(D_METHOD("add_central_force", "force"), &PhysicsDirectBodyState::add_central_force); ClassDB::bind_method(D_METHOD("add_force", "force", "position"), &PhysicsDirectBodyState::add_force); ClassDB::bind_method(D_METHOD("add_torque", "torque"), &PhysicsDirectBodyState::add_torque); + ClassDB::bind_method(D_METHOD("apply_central_impulse", "j"), &PhysicsDirectBodyState::apply_central_impulse); ClassDB::bind_method(D_METHOD("apply_impulse", "position", "j"), &PhysicsDirectBodyState::apply_impulse); ClassDB::bind_method(D_METHOD("apply_torque_impulse", "j"), &PhysicsDirectBodyState::apply_torque_impulse); @@ -105,6 +106,7 @@ void PhysicsDirectBodyState::_bind_methods() { ClassDB::bind_method(D_METHOD("get_contact_local_position", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_position); ClassDB::bind_method(D_METHOD("get_contact_local_normal", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_normal); + ClassDB::bind_method(D_METHOD("get_contact_impulse", "contact_idx"), &PhysicsDirectBodyState::get_contact_impulse); ClassDB::bind_method(D_METHOD("get_contact_local_shape", "contact_idx"), &PhysicsDirectBodyState::get_contact_local_shape); ClassDB::bind_method(D_METHOD("get_contact_collider", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider); ClassDB::bind_method(D_METHOD("get_contact_collider_position", "contact_idx"), &PhysicsDirectBodyState::get_contact_collider_position); @@ -191,7 +193,7 @@ Vector<RID> PhysicsShapeQueryParameters::get_exclude() const { ret.resize(exclude.size()); int idx = 0; for (Set<RID>::Element *E = exclude.front(); E; E = E->next()) { - ret[idx] = E->get(); + ret.write[idx] = E->get(); } return ret; } @@ -495,6 +497,11 @@ void PhysicsServer::_bind_methods() { ClassDB::bind_method(D_METHOD("body_set_state", "body", "state", "value"), &PhysicsServer::body_set_state); ClassDB::bind_method(D_METHOD("body_get_state", "body", "state"), &PhysicsServer::body_get_state); + ClassDB::bind_method(D_METHOD("body_add_central_force", "body", "force"), &PhysicsServer::body_add_central_force); + ClassDB::bind_method(D_METHOD("body_add_force", "body", "force", "position"), &PhysicsServer::body_add_force); + ClassDB::bind_method(D_METHOD("body_add_torque", "body", "torque"), &PhysicsServer::body_add_torque); + + ClassDB::bind_method(D_METHOD("body_apply_central_impulse", "body", "impulse"), &PhysicsServer::body_apply_central_impulse); ClassDB::bind_method(D_METHOD("body_apply_impulse", "body", "position", "impulse"), &PhysicsServer::body_apply_impulse); ClassDB::bind_method(D_METHOD("body_apply_torque_impulse", "body", "impulse"), &PhysicsServer::body_apply_torque_impulse); ClassDB::bind_method(D_METHOD("body_set_axis_velocity", "body", "axis_velocity"), &PhysicsServer::body_set_axis_velocity); diff --git a/servers/physics_server.h b/servers/physics_server.h index 8ecf17c0e6..948aec1a2d 100644 --- a/servers/physics_server.h +++ b/servers/physics_server.h @@ -66,6 +66,7 @@ public: virtual void add_central_force(const Vector3 &p_force) = 0; virtual void add_force(const Vector3 &p_force, const Vector3 &p_pos) = 0; virtual void add_torque(const Vector3 &p_torque) = 0; + virtual void apply_central_impulse(const Vector3 &p_j) = 0; virtual void apply_impulse(const Vector3 &p_pos, const Vector3 &p_j) = 0; virtual void apply_torque_impulse(const Vector3 &p_j) = 0; @@ -76,6 +77,7 @@ public: virtual Vector3 get_contact_local_position(int p_contact_idx) const = 0; virtual Vector3 get_contact_local_normal(int p_contact_idx) const = 0; + virtual float get_contact_impulse(int p_contact_idx) const = 0; virtual int get_contact_local_shape(int p_contact_idx) const = 0; virtual RID get_contact_collider(int p_contact_idx) const = 0; @@ -421,6 +423,11 @@ public: virtual void body_set_applied_torque(RID p_body, const Vector3 &p_torque) = 0; virtual Vector3 body_get_applied_torque(RID p_body) const = 0; + virtual void body_add_central_force(RID p_body, const Vector3 &p_force) = 0; + virtual void body_add_force(RID p_body, const Vector3 &p_force, const Vector3 &p_pos) = 0; + virtual void body_add_torque(RID p_body, const Vector3 &p_torque) = 0; + + virtual void body_apply_central_impulse(RID p_body, const Vector3 &p_impulse) = 0; virtual void body_apply_impulse(RID p_body, const Vector3 &p_pos, const Vector3 &p_impulse) = 0; virtual void body_apply_torque_impulse(RID p_body, const Vector3 &p_impulse) = 0; virtual void body_set_axis_velocity(RID p_body, const Vector3 &p_axis_velocity) = 0; @@ -477,6 +484,72 @@ public: virtual bool body_test_motion(RID p_body, const Transform &p_from, const Vector3 &p_motion, bool p_infinite_inertia, MotionResult *r_result = NULL) = 0; + /* SOFT BODY */ + + virtual RID soft_body_create(bool p_init_sleeping = false) = 0; + + virtual void soft_body_update_visual_server(RID p_body, class SoftBodyVisualServerHandler *p_visual_server_handler) = 0; + + virtual void soft_body_set_space(RID p_body, RID p_space) = 0; + virtual RID soft_body_get_space(RID p_body) const = 0; + + virtual void soft_body_set_mesh(RID p_body, const REF &p_mesh) = 0; + + virtual void soft_body_set_collision_layer(RID p_body, uint32_t p_layer) = 0; + virtual uint32_t soft_body_get_collision_layer(RID p_body) const = 0; + + virtual void soft_body_set_collision_mask(RID p_body, uint32_t p_mask) = 0; + virtual uint32_t soft_body_get_collision_mask(RID p_body) const = 0; + + virtual void soft_body_add_collision_exception(RID p_body, RID p_body_b) = 0; + virtual void soft_body_remove_collision_exception(RID p_body, RID p_body_b) = 0; + virtual void soft_body_get_collision_exceptions(RID p_body, List<RID> *p_exceptions) = 0; + + virtual void soft_body_set_state(RID p_body, BodyState p_state, const Variant &p_variant) = 0; + virtual Variant soft_body_get_state(RID p_body, BodyState p_state) const = 0; + + virtual void soft_body_set_transform(RID p_body, const Transform &p_transform) = 0; + virtual Vector3 soft_body_get_vertex_position(RID p_body, int vertex_index) const = 0; + + virtual void soft_body_set_ray_pickable(RID p_body, bool p_enable) = 0; + virtual bool soft_body_is_ray_pickable(RID p_body) const = 0; + + virtual void soft_body_set_simulation_precision(RID p_body, int p_simulation_precision) = 0; + virtual int soft_body_get_simulation_precision(RID p_body) = 0; + + virtual void soft_body_set_total_mass(RID p_body, real_t p_total_mass) = 0; + virtual real_t soft_body_get_total_mass(RID p_body) = 0; + + virtual void soft_body_set_linear_stiffness(RID p_body, real_t p_stiffness) = 0; + virtual real_t soft_body_get_linear_stiffness(RID p_body) = 0; + + virtual void soft_body_set_areaAngular_stiffness(RID p_body, real_t p_stiffness) = 0; + virtual real_t soft_body_get_areaAngular_stiffness(RID p_body) = 0; + + virtual void soft_body_set_volume_stiffness(RID p_body, real_t p_stiffness) = 0; + virtual real_t soft_body_get_volume_stiffness(RID p_body) = 0; + + virtual void soft_body_set_pressure_coefficient(RID p_body, real_t p_pressure_coefficient) = 0; + virtual real_t soft_body_get_pressure_coefficient(RID p_body) = 0; + + virtual void soft_body_set_pose_matching_coefficient(RID p_body, real_t p_pose_matching_coefficient) = 0; + virtual real_t soft_body_get_pose_matching_coefficient(RID p_body) = 0; + + virtual void soft_body_set_damping_coefficient(RID p_body, real_t p_damping_coefficient) = 0; + virtual real_t soft_body_get_damping_coefficient(RID p_body) = 0; + + virtual void soft_body_set_drag_coefficient(RID p_body, real_t p_drag_coefficient) = 0; + virtual real_t soft_body_get_drag_coefficient(RID p_body) = 0; + + virtual void soft_body_move_point(RID p_body, int p_point_index, const Vector3 &p_global_position) = 0; + virtual Vector3 soft_body_get_point_global_position(RID p_body, int p_point_index) = 0; + + virtual Vector3 soft_body_get_point_offset(RID p_body, int p_point_index) const = 0; + + virtual void soft_body_remove_all_pinned_points(RID p_body) = 0; + virtual void soft_body_pin_point(RID p_body, int p_point_index, bool p_pin) = 0; + virtual bool soft_body_is_point_pinned(RID p_body, int p_point_index) = 0; + /* JOINT API */ enum JointType { diff --git a/servers/register_server_types.cpp b/servers/register_server_types.cpp index 1bad7e652b..4c764641e3 100644 --- a/servers/register_server_types.cpp +++ b/servers/register_server_types.cpp @@ -48,6 +48,7 @@ #include "audio/effects/audio_effect_panner.h" #include "audio/effects/audio_effect_phaser.h" #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_stereo_enhance.h" #include "audio_server.h" @@ -72,7 +73,7 @@ static void _debugger_get_resource_usage(List<ScriptDebuggerRemote::ResourceUsag usage.vram = E->get().bytes; usage.id = E->get().texture; usage.type = "Texture"; - usage.format = itos(E->get().size.width) + "x" + itos(E->get().size.height) + " " + Image::get_format_name(E->get().format); + usage.format = itos(E->get().width) + "x" + itos(E->get().height) + " " + Image::get_format_name(E->get().format); r_usage->push_back(usage); } } @@ -103,6 +104,7 @@ void register_server_types() { ClassDB::register_virtual_class<AudioStream>(); ClassDB::register_virtual_class<AudioStreamPlayback>(); + ClassDB::register_class<AudioStreamMicrophone>(); ClassDB::register_class<AudioStreamRandomPitch>(); ClassDB::register_virtual_class<AudioEffect>(); ClassDB::register_class<AudioEffectEQ>(); @@ -138,6 +140,7 @@ void register_server_types() { ClassDB::register_class<AudioEffectLimiter>(); ClassDB::register_class<AudioEffectPitchShift>(); ClassDB::register_class<AudioEffectPhaser>(); + ClassDB::register_class<AudioEffectRecord>(); } ClassDB::register_virtual_class<Physics2DDirectBodyState>(); diff --git a/servers/server_wrap_mt_common.h b/servers/server_wrap_mt_common.h index 611e25af2a..843773e5b1 100644 --- a/servers/server_wrap_mt_common.h +++ b/servers/server_wrap_mt_common.h @@ -197,9 +197,10 @@ } #define FUNC5RID(m_type, m_arg1, m_arg2, m_arg3, m_arg4, m_arg5) \ - int m_type##allocn() { \ - for (int i = 0; i < m_type##_pool_max_size; i++) { \ - m_type##_id_pool.push_back(server_name->m_type##_create()); \ + List<RID> m_type##_id_pool; \ + int m_type##allocn(m_arg1 p1, m_arg2 p2, m_arg3 p3, m_arg4 p4, m_arg5 p5) { \ + for (int i = 0; i < pool_max_size; i++) { \ + m_type##_id_pool.push_back(server_name->m_type##_create(p1, p2, p3, p4, p5)); \ } \ return 0; \ } \ diff --git a/servers/visual/rasterizer.h b/servers/visual/rasterizer.h index 0b37d266e7..49dff0d557 100644 --- a/servers/visual/rasterizer.h +++ b/servers/visual/rasterizer.h @@ -104,10 +104,12 @@ public: VS::ShadowCastingSetting cast_shadows; + //fit in 32 bits bool mirror : 8; bool receive_shadows : 8; bool visible : 8; - bool baked_light : 8; //this flag is only to know if it actually did use baked light + bool baked_light : 4; //this flag is only to know if it actually did use baked light + bool redraw_if_visible : 4; float depth; //used for sorting @@ -131,6 +133,7 @@ public: depth_layer = 0; layer_mask = 1; baked_light = false; + redraw_if_visible = false; lightmap_capture = NULL; } }; @@ -173,17 +176,34 @@ public: /* TEXTURE API */ virtual RID texture_create() = 0; - virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) = 0; - virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) = 0; - virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) = 0; - virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const = 0; + virtual void texture_allocate(RID p_texture, + int p_width, + int p_height, + int p_depth_3d, + Image::Format p_format, + VS::TextureType p_type, + uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) = 0; + + virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level = 0) = 0; + + virtual void texture_set_data_partial(RID p_texture, + const Ref<Image> &p_image, + int src_x, int src_y, + int src_w, int src_h, + int dst_x, int dst_y, + int p_dst_mip, + int p_level = 0) = 0; + + virtual Ref<Image> texture_get_data(RID p_texture, int p_level = 0) const = 0; virtual void texture_set_flags(RID p_texture, uint32_t p_flags) = 0; virtual uint32_t texture_get_flags(RID p_texture) const = 0; virtual Image::Format texture_get_format(RID p_texture) const = 0; + virtual VS::TextureType texture_get_type(RID p_texture) const = 0; virtual uint32_t texture_get_texid(RID p_texture) const = 0; virtual uint32_t texture_get_width(RID p_texture) const = 0; virtual uint32_t texture_get_height(RID p_texture) const = 0; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; + virtual uint32_t texture_get_depth(RID p_texture) const = 0; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) = 0; virtual void texture_set_path(RID p_texture, const String &p_path) = 0; virtual String texture_get_path(RID p_texture) const = 0; @@ -277,6 +297,7 @@ public: virtual AABB mesh_get_custom_aabb(RID p_mesh) const = 0; virtual AABB mesh_get_aabb(RID p_mesh, RID p_skeleton) const = 0; + virtual void mesh_clear(RID p_mesh) = 0; /* MULTIMESH API */ @@ -1074,7 +1095,7 @@ public: virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) = 0; virtual void initialize() = 0; - virtual void begin_frame() = 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 clear_render_target(const Color &p_color) = 0; diff --git a/servers/visual/shader_language.cpp b/servers/visual/shader_language.cpp index fd1eb77143..ca50d0d049 100644 --- a/servers/visual/shader_language.cpp +++ b/servers/visual/shader_language.cpp @@ -123,6 +123,12 @@ const char *ShaderLanguage::token_names[TK_MAX] = { "TYPE_SAMPLER2D", "TYPE_ISAMPLER2D", "TYPE_USAMPLER2D", + "TYPE_SAMPLER2DARRAY", + "TYPE_ISAMPLER2DARRAY", + "TYPE_USAMPLER2DARRAY", + "TYPE_SAMPLER3D", + "TYPE_ISAMPLER3D", + "TYPE_USAMPLER3D", "TYPE_SAMPLERCUBE", "INTERPOLATION_FLAT", "INTERPOLATION_NO_PERSPECTIVE", @@ -257,6 +263,12 @@ const ShaderLanguage::KeyWord ShaderLanguage::keyword_list[] = { { TK_TYPE_SAMPLER2D, "sampler2D" }, { TK_TYPE_ISAMPLER2D, "isampler2D" }, { TK_TYPE_USAMPLER2D, "usampler2D" }, + { TK_TYPE_SAMPLER2DARRAY, "sampler2DArray" }, + { TK_TYPE_ISAMPLER2DARRAY, "isampler2DArray" }, + { TK_TYPE_USAMPLER2DARRAY, "usampler2DArray" }, + { TK_TYPE_SAMPLER3D, "sampler3D" }, + { TK_TYPE_ISAMPLER3D, "isampler3D" }, + { TK_TYPE_USAMPLER3D, "usampler3D" }, { TK_TYPE_SAMPLERCUBE, "samplerCube" }, { TK_INTERPOLATION_FLAT, "flat" }, { TK_INTERPOLATION_NO_PERSPECTIVE, "noperspective" }, @@ -516,13 +528,14 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { bool hexa_found = false; bool sign_found = false; bool minus_exponent_found = false; + bool float_suffix_found = false; String str; int i = 0; while (true) { if (GETCHAR(i) == '.') { - if (period_found || exponent_found) + if (period_found || exponent_found || hexa_found || float_suffix_found) return _make_token(TK_ERROR, "Invalid numeric constant"); period_found = true; } else if (GETCHAR(i) == 'x') { @@ -530,11 +543,16 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { return _make_token(TK_ERROR, "Invalid numeric constant"); hexa_found = true; } else if (GETCHAR(i) == 'e') { - if (hexa_found || exponent_found) + if (hexa_found || exponent_found || float_suffix_found) return _make_token(TK_ERROR, "Invalid numeric constant"); exponent_found = true; + } else if (GETCHAR(i) == 'f') { + if (hexa_found || exponent_found) + return _make_token(TK_ERROR, "Invalid numeric constant"); + float_suffix_found = true; } else if (_is_number(GETCHAR(i))) { - //all ok + if (float_suffix_found) + return _make_token(TK_ERROR, "Invalid numeric constant"); } else if (hexa_found && _is_hex(GETCHAR(i))) { } else if ((GETCHAR(i) == '-' || GETCHAR(i) == '+') && exponent_found) { @@ -550,21 +568,60 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { i++; } - if (!_is_number(str[str.length() - 1])) - return _make_token(TK_ERROR, "Invalid numeric constant"); + CharType last_char = str[str.length() - 1]; + + if (hexa_found) { + //hex integers eg."0xFF" or "0x12AB", etc - NOT supported yet + return _make_token(TK_ERROR, "Invalid (hexadecimal) numeric constant - Not supported"); + } else if (period_found || float_suffix_found) { + //floats + if (period_found) { + if (float_suffix_found) { + //checks for eg "1.f" or "1.99f" notations + if (last_char != 'f') { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + } else { + //checks for eg. "1." or "1.99" notations + if (last_char != '.' && !_is_number(last_char)) { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + } + } else if (float_suffix_found) { + // if no period found the float suffix must be the last character, like in "2f" for "2.0" + if (last_char != 'f') { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + } + + if (float_suffix_found) { + //strip the suffix + str = str.left(str.length() - 1); + //compensate reading cursor position + char_idx += 1; + } + + if (!str.is_valid_float()) { + return _make_token(TK_ERROR, "Invalid (float) numeric constant"); + } + } else { + //integers + if (!_is_number(last_char)) { + return _make_token(TK_ERROR, "Invalid (integer) numeric constant"); + } + if (!str.is_valid_integer()) { + return _make_token(TK_ERROR, "Invalid numeric constant"); + } + } char_idx += str.length(); Token tk; - if (period_found || minus_exponent_found) + if (period_found || minus_exponent_found || float_suffix_found) tk.type = TK_REAL_CONSTANT; else tk.type = TK_INT_CONSTANT; - if (!str.is_valid_float()) { - return _make_token(TK_ERROR, "Invalid numeric constant"); - } - - tk.constant = str.to_double(); + tk.constant = str.to_double(); //wont work with hex tk.line = tk_line; return tk; @@ -612,6 +669,8 @@ ShaderLanguage::Token ShaderLanguage::_get_token() { } ERR_PRINT("BUG"); return Token(); + +#undef GETCHAR } String ShaderLanguage::token_debug(const String &p_code) { @@ -658,6 +717,12 @@ bool ShaderLanguage::is_token_datatype(TokenType p_type) { p_type == TK_TYPE_SAMPLER2D || p_type == TK_TYPE_ISAMPLER2D || p_type == TK_TYPE_USAMPLER2D || + p_type == TK_TYPE_SAMPLER2DARRAY || + p_type == TK_TYPE_ISAMPLER2DARRAY || + p_type == TK_TYPE_USAMPLER2DARRAY || + p_type == TK_TYPE_SAMPLER3D || + p_type == TK_TYPE_ISAMPLER3D || + p_type == TK_TYPE_USAMPLER3D || p_type == TK_TYPE_SAMPLERCUBE); } @@ -729,6 +794,12 @@ String ShaderLanguage::get_datatype_name(DataType p_type) { case TYPE_SAMPLER2D: return "sampler2D"; case TYPE_ISAMPLER2D: return "isampler2D"; case TYPE_USAMPLER2D: return "usampler2D"; + case TYPE_SAMPLER2DARRAY: return "sampler2DArray"; + case TYPE_ISAMPLER2DARRAY: return "isampler2DArray"; + case TYPE_USAMPLER2DARRAY: return "usampler2DArray"; + case TYPE_SAMPLER3D: return "sampler3D"; + case TYPE_ISAMPLER3D: return "isampler3D"; + case TYPE_USAMPLER3D: return "usampler3D"; case TYPE_SAMPLERCUBE: return "samplerCube"; } @@ -1376,6 +1447,15 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "bvec4", TYPE_BVEC4, { TYPE_UVEC4, TYPE_VOID } }, { "bvec4", TYPE_BVEC4, { TYPE_VEC4, TYPE_VOID } }, + //conversion between matrixes + + { "mat2", TYPE_MAT2, { TYPE_MAT3, TYPE_VOID } }, + { "mat2", TYPE_MAT2, { TYPE_MAT4, TYPE_VOID } }, + { "mat3", TYPE_MAT3, { TYPE_MAT2, TYPE_VOID } }, + { "mat3", TYPE_MAT3, { TYPE_MAT4, TYPE_VOID } }, + { "mat4", TYPE_MAT4, { TYPE_MAT2, TYPE_VOID } }, + { "mat4", TYPE_MAT4, { TYPE_MAT3, TYPE_VOID } }, + //builtins - trigonometry { "radians", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID } }, @@ -1791,6 +1871,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureSize", TYPE_IVEC2, { TYPE_SAMPLER2D, TYPE_INT, TYPE_VOID } }, { "textureSize", TYPE_IVEC2, { TYPE_ISAMPLER2D, TYPE_INT, TYPE_VOID } }, { "textureSize", TYPE_IVEC2, { TYPE_USAMPLER2D, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER2DARRAY, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER2DARRAY, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER2DARRAY, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_SAMPLER3D, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_ISAMPLER3D, TYPE_INT, TYPE_VOID } }, + { "textureSize", TYPE_IVEC3, { TYPE_USAMPLER3D, TYPE_INT, TYPE_VOID } }, { "textureSize", TYPE_IVEC2, { TYPE_SAMPLERCUBE, TYPE_INT, TYPE_VOID } }, { "texture", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VOID } }, @@ -1802,6 +1888,24 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VOID } }, { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + + { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VOID } }, + { "texture", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VOID } }, { "texture", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, @@ -1820,15 +1924,38 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, + { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_VOID } }, + { "textureProj", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, + + { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_VOID } }, + { "textureProj", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, + + { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_VOID } }, + { "textureProj", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } }, { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } }, { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, + { "textureLod", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, { "textureLod", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } }, { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } }, { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_IVEC2, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + + { "texelFetch", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "texelFetch", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_IVEC3, TYPE_INT, TYPE_VOID } }, + { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC3, TYPE_FLOAT, TYPE_VOID } }, { "textureProjLod", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC4, TYPE_FLOAT, TYPE_VOID } }, @@ -1841,6 +1968,12 @@ const ShaderLanguage::BuiltinFuncDef ShaderLanguage::builtin_func_defs[] = { { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2D, TYPE_VEC2, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, + { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, + { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, + { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER2DARRAY, TYPE_VEC3, TYPE_VEC2, TYPE_VEC2, TYPE_VOID } }, + { "textureGrad", TYPE_VEC4, { TYPE_SAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, + { "textureGrad", TYPE_IVEC4, { TYPE_ISAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, + { "textureGrad", TYPE_UVEC4, { TYPE_USAMPLER3D, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, { "textureGrad", TYPE_VEC4, { TYPE_SAMPLERCUBE, TYPE_VEC3, TYPE_VEC3, TYPE_VEC3, TYPE_VOID } }, { "dFdx", TYPE_FLOAT, { TYPE_FLOAT, TYPE_VOID } }, @@ -2128,7 +2261,16 @@ bool ShaderLanguage::is_scalar_type(DataType p_type) { bool ShaderLanguage::is_sampler_type(DataType p_type) { - return p_type == TYPE_SAMPLER2D || p_type == TYPE_ISAMPLER2D || p_type == TYPE_USAMPLER2D || p_type == TYPE_SAMPLERCUBE; + return p_type == TYPE_SAMPLER2D || + p_type == TYPE_ISAMPLER2D || + p_type == TYPE_USAMPLER2D || + p_type == TYPE_SAMPLER2DARRAY || + p_type == TYPE_ISAMPLER2DARRAY || + p_type == TYPE_USAMPLER2DARRAY || + p_type == TYPE_SAMPLER3D || + p_type == TYPE_ISAMPLER3D || + p_type == TYPE_USAMPLER3D || + p_type == TYPE_SAMPLERCUBE; } void ShaderLanguage::get_keyword_list(List<String> *r_keywords) { @@ -2295,24 +2437,54 @@ bool ShaderLanguage::_is_operator_assign(Operator p_op) const { return false; } -bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types) { +bool ShaderLanguage::_validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message) { if (p_node->type == Node::TYPE_OPERATOR) { OperatorNode *op = static_cast<OperatorNode *>(p_node); + if (op->op == OP_INDEX) { - return _validate_assign(op->arguments[0], p_builtin_types); + return _validate_assign(op->arguments[0], p_builtin_types, r_message); + + } else if (_is_operator_assign(op->op)) { + //chained assignment + return _validate_assign(op->arguments[1], p_builtin_types, r_message); + + } else if (op->op == OP_CALL) { + if (r_message) + *r_message = RTR("Assignment to function."); + return false; } - } - if (p_node->type == Node::TYPE_VARIABLE) { + } else if (p_node->type == Node::TYPE_MEMBER) { + + MemberNode *member = static_cast<MemberNode *>(p_node); + return _validate_assign(member->owner, p_builtin_types, r_message); + + } else if (p_node->type == Node::TYPE_VARIABLE) { VariableNode *var = static_cast<VariableNode *>(p_node); - if (p_builtin_types.has(var->name) && p_builtin_types[var->name].constant) { - return false; //ops not valid + + if (shader->uniforms.has(var->name)) { + if (r_message) + *r_message = RTR("Assignment to uniform."); + return false; + } + + if (shader->varyings.has(var->name) && current_function != String("vertex")) { + if (r_message) + *r_message = RTR("Varyings can only be assigned in vertex function."); + return false; + } + + if (!(p_builtin_types.has(var->name) && p_builtin_types[var->name].constant)) { + return true; } } - return true; + + if (r_message) + *r_message = "Assignment to constant expression."; + return false; } ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types) { @@ -2460,7 +2632,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons //add to current function as dependency for (int j = 0; j < shader->functions.size(); j++) { if (shader->functions[j].name == current_function) { - shader->functions[j].uses_function.insert(name); + shader->functions.write[j].uses_function.insert(name); break; } } @@ -3010,8 +3182,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons } op->arguments.push_back(expression[i + 1].node); - expression[i].is_op = false; - expression[i].node = op; + expression.write[i].is_op = false; + expression.write[i].node = op; if (!_validate_operator(op, &op->return_cache)) { @@ -3045,8 +3217,8 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons op->arguments.push_back(expression[next_op + 1].node); op->arguments.push_back(expression[next_op + 3].node); - expression[next_op - 1].is_op = false; - expression[next_op - 1].node = op; + expression.write[next_op - 1].is_op = false; + expression.write[next_op - 1].node = op; if (!_validate_operator(op, &op->return_cache)) { String at; @@ -3079,10 +3251,14 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons ERR_FAIL_V(NULL); } - if (_is_operator_assign(op->op) && !_validate_assign(expression[next_op - 1].node, p_builtin_types)) { + if (_is_operator_assign(op->op)) { - _set_error("Assignment to constant expression."); - return NULL; + String assign_message; + if (!_validate_assign(expression[next_op - 1].node, p_builtin_types, &assign_message)) { + + _set_error(assign_message); + return NULL; + } } if (expression[next_op + 1].is_op) { @@ -3096,7 +3272,7 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons op->arguments.push_back(expression[next_op - 1].node); //expression goes as left op->arguments.push_back(expression[next_op + 1].node); //next expression goes as right - expression[next_op - 1].node = op; + expression.write[next_op - 1].node = op; //replace all 3 nodes by this operator and make it an expression @@ -3138,7 +3314,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha for (int i = 1; i < op->arguments.size(); i++) { - op->arguments[i] = _reduce_expression(p_block, op->arguments[i]); + op->arguments.write[i] = _reduce_expression(p_block, op->arguments[i]); if (op->arguments[i]->type == Node::TYPE_CONSTANT) { ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[i]); @@ -3178,7 +3354,7 @@ ShaderLanguage::Node *ShaderLanguage::_reduce_expression(BlockNode *p_block, Sha return cn; } else if (op->op == OP_NEGATE) { - op->arguments[0] = _reduce_expression(p_block, op->arguments[0]); + op->arguments.write[0] = _reduce_expression(p_block, op->arguments[0]); if (op->arguments[0]->type == Node::TYPE_CONSTANT) { ConstantNode *cn = static_cast<ConstantNode *>(op->arguments[0]); @@ -4064,13 +4240,58 @@ Error ShaderLanguage::_parse_shader(const Map<StringName, FunctionInfo> &p_funct return OK; } +// skips over whitespace and /* */ and // comments +static int _get_first_ident_pos(const String &p_code) { + + int idx = 0; + +#define GETCHAR(m_idx) (((idx + m_idx) < p_code.length()) ? p_code[idx + m_idx] : CharType(0)) + + while (true) { + if (GETCHAR(0) == '/' && GETCHAR(1) == '/') { + idx += 2; + while (true) { + if (GETCHAR(0) == 0) return 0; + if (GETCHAR(0) == '\n') { + idx++; + break; // loop + } + idx++; + } + } else if (GETCHAR(0) == '/' && GETCHAR(1) == '*') { + idx += 2; + while (true) { + if (GETCHAR(0) == 0) return 0; + if (GETCHAR(0) == '*' && GETCHAR(1) == '/') { + idx += 2; + break; // loop + } + idx++; + } + } else { + switch (GETCHAR(0)) { + case ' ': + case '\t': + case '\r': + case '\n': { + idx++; + } break; // switch + default: + return idx; + } + } + } + +#undef GETCHAR +} + String ShaderLanguage::get_shader_type(const String &p_code) { bool reading_type = false; String cur_identifier; - for (int i = 0; i < p_code.length(); i++) { + for (int i = _get_first_ident_pos(p_code); i < p_code.length(); i++) { if (p_code[i] == ';') { break; diff --git a/servers/visual/shader_language.h b/servers/visual/shader_language.h index 9b84c5f195..d68f233b2f 100644 --- a/servers/visual/shader_language.h +++ b/servers/visual/shader_language.h @@ -72,6 +72,12 @@ public: TK_TYPE_SAMPLER2D, TK_TYPE_ISAMPLER2D, TK_TYPE_USAMPLER2D, + TK_TYPE_SAMPLER2DARRAY, + TK_TYPE_ISAMPLER2DARRAY, + TK_TYPE_USAMPLER2DARRAY, + TK_TYPE_SAMPLER3D, + TK_TYPE_ISAMPLER3D, + TK_TYPE_USAMPLER3D, TK_TYPE_SAMPLERCUBE, TK_INTERPOLATION_FLAT, TK_INTERPOLATION_NO_PERSPECTIVE, @@ -186,6 +192,12 @@ public: TYPE_SAMPLER2D, TYPE_ISAMPLER2D, TYPE_USAMPLER2D, + TYPE_SAMPLER2DARRAY, + TYPE_ISAMPLER2DARRAY, + TYPE_USAMPLER2DARRAY, + TYPE_SAMPLER3D, + TYPE_ISAMPLER3D, + TYPE_USAMPLER3D, TYPE_SAMPLERCUBE, }; @@ -617,7 +629,7 @@ private: bool _find_identifier(const BlockNode *p_block, const Map<StringName, BuiltInInfo> &p_builtin_types, const StringName &p_identifier, DataType *r_data_type = NULL, IdentifierType *r_type = NULL); bool _is_operator_assign(Operator p_op) const; - bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types); + bool _validate_assign(Node *p_node, const Map<StringName, BuiltInInfo> &p_builtin_types, String *r_message = NULL); bool _validate_operator(OperatorNode *p_op, DataType *r_ret_type = NULL); diff --git a/servers/visual/visual_server_canvas.cpp b/servers/visual/visual_server_canvas.cpp index 6439ba8509..0b4bbffddf 100644 --- a/servers/visual/visual_server_canvas.cpp +++ b/servers/visual/visual_server_canvas.cpp @@ -220,7 +220,7 @@ void VisualServerCanvas::render_canvas(Canvas *p_canvas, const Transform2D &p_tr for (int i = 0; i < l; i++) { - Canvas::ChildItem &ci = p_canvas->child_items[i]; + const Canvas::ChildItem &ci = p_canvas->child_items[i]; _render_canvas_item_tree(ci.item, p_transform, p_clip_rect, p_canvas->modulate, p_lights); //mirroring (useful for scrolling backgrounds) @@ -263,7 +263,7 @@ void VisualServerCanvas::canvas_set_item_mirroring(RID p_canvas, RID p_item, con int idx = canvas->find_item(canvas_item); ERR_FAIL_COND(idx == -1); - canvas->child_items[idx].mirror = p_mirroring; + canvas->child_items.write[idx].mirror = p_mirroring; } void VisualServerCanvas::canvas_set_modulate(RID p_canvas, const Color &p_color) { @@ -468,21 +468,21 @@ void VisualServerCanvas::canvas_item_add_polyline(RID p_item, const Vector<Point Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5; if (p_antialiased) { - pline->lines[i] = p_points[i] + tangent; - pline->lines[p_points.size() * 2 - i - 1] = p_points[i] - tangent; + pline->lines.write[i] = p_points[i] + tangent; + pline->lines.write[p_points.size() * 2 - i - 1] = p_points[i] - tangent; if (pline->line_colors.size() > 1) { - pline->line_colors[i] = p_colors[i]; - pline->line_colors[p_points.size() * 2 - i - 1] = p_colors[i]; + pline->line_colors.write[i] = p_colors[i]; + pline->line_colors.write[p_points.size() * 2 - i - 1] = p_colors[i]; } } - pline->triangles[i * 2 + 0] = p_points[i] + tangent; - pline->triangles[i * 2 + 1] = p_points[i] - tangent; + pline->triangles.write[i * 2 + 0] = p_points[i] + tangent; + pline->triangles.write[i * 2 + 1] = p_points[i] - tangent; if (pline->triangle_colors.size() > 1) { - pline->triangle_colors[i * 2 + 0] = p_colors[i]; - pline->triangle_colors[i * 2 + 1] = p_colors[i]; + pline->triangle_colors.write[i * 2 + 0] = p_colors[i]; + pline->triangle_colors.write[i * 2 + 1] = p_colors[i]; } prev_t = t; @@ -669,7 +669,7 @@ void VisualServerCanvas::canvas_item_add_polygon(RID p_item, const Vector<Point2 int color_size = p_colors.size(); int uv_size = p_uvs.size(); ERR_FAIL_COND(color_size != 0 && color_size != 1 && color_size != pointcount); - ERR_FAIL_COND(uv_size != 0 && (uv_size != pointcount || !p_texture.is_valid())); + ERR_FAIL_COND(uv_size != 0 && (uv_size != pointcount)); #endif Vector<int> indices = Geometry::triangulate_polygon(p_points); diff --git a/servers/visual/visual_server_raster.cpp b/servers/visual/visual_server_raster.cpp index 5f207b1d3f..c7d33ec43c 100644 --- a/servers/visual/visual_server_raster.cpp +++ b/servers/visual/visual_server_raster.cpp @@ -93,14 +93,14 @@ void VisualServerRaster::request_frame_drawn_callback(Object *p_where, const Str frame_drawn_callbacks.push_back(fdc); } -void VisualServerRaster::draw(bool p_swap_buffers) { +void VisualServerRaster::draw(bool p_swap_buffers, double frame_step) { //needs to be done before changes is reset to 0, to not force the editor to redraw VS::get_singleton()->emit_signal("frame_pre_draw"); changes = 0; - VSG::rasterizer->begin_frame(); + VSG::rasterizer->begin_frame(frame_step); VSG::scene->update_dirty_instances(); //update scene stuff @@ -161,6 +161,7 @@ void VisualServerRaster::set_boot_image(const Ref<Image> &p_image, const Color & VSG::rasterizer->set_boot_image(p_image, p_color, p_scale); } void VisualServerRaster::set_default_clear_color(const Color &p_color) { + VSG::viewport->set_default_clear_color(p_color); } bool VisualServerRaster::has_feature(Features p_feature) const { diff --git a/servers/visual/visual_server_raster.h b/servers/visual/visual_server_raster.h index ec0d02ed2a..a00b364565 100644 --- a/servers/visual/visual_server_raster.h +++ b/servers/visual/visual_server_raster.h @@ -148,17 +148,19 @@ public: /* TEXTURE API */ BIND0R(RID, texture_create) - BIND5(texture_allocate, RID, int, int, Image::Format, uint32_t) - BIND3(texture_set_data, RID, const Ref<Image> &, CubeMapSide) - BIND10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, CubeMapSide) - BIND2RC(Ref<Image>, texture_get_data, RID, CubeMapSide) + BIND7(texture_allocate, RID, int, int, int, Image::Format, TextureType, uint32_t) + BIND3(texture_set_data, RID, const Ref<Image> &, int) + BIND10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, int) + BIND2RC(Ref<Image>, texture_get_data, RID, int) BIND2(texture_set_flags, RID, uint32_t) BIND1RC(uint32_t, texture_get_flags, RID) BIND1RC(Image::Format, texture_get_format, RID) + BIND1RC(TextureType, texture_get_type, RID) BIND1RC(uint32_t, texture_get_texid, RID) BIND1RC(uint32_t, texture_get_width, RID) BIND1RC(uint32_t, texture_get_height, RID) - BIND3(texture_set_size_override, RID, int, int) + BIND1RC(uint32_t, texture_get_depth, RID) + BIND4(texture_set_size_override, RID, int, int, int) BIND3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *) BIND3(texture_set_detect_srgb_callback, RID, TextureDetectCallback, void *) @@ -660,7 +662,7 @@ public: virtual void request_frame_drawn_callback(Object *p_where, const StringName &p_method, const Variant &p_userdata); - virtual void draw(bool p_swap_buffers); + virtual void draw(bool p_swap_buffers, double frame_step); virtual void sync(); virtual bool has_changed() const; virtual void init(); diff --git a/servers/visual/visual_server_scene.cpp b/servers/visual/visual_server_scene.cpp index 34a1f1458a..213b3ad8f6 100644 --- a/servers/visual/visual_server_scene.cpp +++ b/servers/visual/visual_server_scene.cpp @@ -589,7 +589,7 @@ void VisualServerScene::instance_set_blend_shape_weight(RID p_instance, int p_sh } ERR_FAIL_INDEX(p_shape, instance->blend_values.size()); - instance->blend_values[p_shape] = p_weight; + instance->blend_values.write[p_shape] = p_weight; } void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surface, RID p_material) { @@ -606,7 +606,7 @@ void VisualServerScene::instance_set_surface_material(RID p_instance, int p_surf if (instance->materials[p_surface].is_valid()) { VSG::storage->material_remove_instance_owner(instance->materials[p_surface], instance); } - instance->materials[p_surface] = p_material; + instance->materials.write[p_surface] = p_material; instance->base_material_changed(); if (instance->materials[p_surface].is_valid()) { @@ -820,6 +820,11 @@ void VisualServerScene::instance_geometry_set_flag(RID p_instance, VS::InstanceF instance->baked_light = p_enabled; } break; + case VS::INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE: { + + instance->redraw_if_visible = p_enabled; + + } break; } } void VisualServerScene::instance_geometry_set_cast_shadows_setting(RID p_instance, VS::ShadowCastingSetting p_shadow_casting_setting) { @@ -1248,7 +1253,7 @@ void VisualServerScene::_update_instance_lightmap_captures(Instance *p_instance) Vector3 dir = to_cell_xform.basis.xform(cone_traces[i]).normalized(); Color capture = _light_capture_voxel_cone_trace(octree_r.ptr(), pos, dir, cone_aperture, cell_subdiv); - p_instance->lightmap_capture_data[i] += capture; + p_instance->lightmap_capture_data.write[i] += capture; } } } @@ -1459,14 +1464,14 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons light_frustum_planes.resize(6); //right/left - light_frustum_planes[0] = Plane(x_vec, x_max); - light_frustum_planes[1] = Plane(-x_vec, -x_min); + light_frustum_planes.write[0] = Plane(x_vec, x_max); + light_frustum_planes.write[1] = Plane(-x_vec, -x_min); //top/bottom - light_frustum_planes[2] = Plane(y_vec, y_max); - light_frustum_planes[3] = Plane(-y_vec, -y_min); + light_frustum_planes.write[2] = Plane(y_vec, y_max); + light_frustum_planes.write[3] = Plane(-y_vec, -y_min); //near/far - light_frustum_planes[4] = Plane(z_vec, z_max + 1e6); - light_frustum_planes[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed + light_frustum_planes.write[4] = Plane(z_vec, z_max + 1e6); + light_frustum_planes.write[5] = Plane(-z_vec, -z_min); // z_min is ok, since casters further than far-light plane are not needed int cull_count = p_scenario->octree.cull_convex(light_frustum_planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK); @@ -1527,11 +1532,11 @@ void VisualServerScene::_light_instance_update_shadow(Instance *p_instance, cons float z = i == 0 ? -1 : 1; Vector<Plane> planes; planes.resize(5); - planes[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); - planes[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius)); - planes[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius)); - planes[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius)); - planes[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); + planes.write[0] = light_transform.xform(Plane(Vector3(0, 0, z), radius)); + planes.write[1] = light_transform.xform(Plane(Vector3(1, 0, z).normalized(), radius)); + planes.write[2] = light_transform.xform(Plane(Vector3(-1, 0, z).normalized(), radius)); + planes.write[3] = light_transform.xform(Plane(Vector3(0, 1, z).normalized(), radius)); + planes.write[4] = light_transform.xform(Plane(Vector3(0, -1, z).normalized(), radius)); int cull_count = p_scenario->octree.cull_convex(planes, instance_shadow_cull_result, MAX_INSTANCE_CULL, VS::INSTANCE_GEOMETRY_MASK); Plane near_plane(light_transform.origin, light_transform.basis.get_axis(2) * z); @@ -1873,6 +1878,10 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(ins->base_data); + if (ins->redraw_if_visible) { + VisualServerRaster::redraw_request(); + } + if (ins->base_type == VS::INSTANCE_PARTICLES) { //particles visible? process them VSG::storage->particles_request_process(ins->base); @@ -1889,7 +1898,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceLightData *light = static_cast<InstanceLightData *>(E->get()->base_data); - ins->light_instances[l++] = light->instance; + ins->light_instances.write[l++] = light->instance; } geom->lighting_dirty = false; @@ -1904,7 +1913,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceReflectionProbeData *reflection_probe = static_cast<InstanceReflectionProbeData *>(E->get()->base_data); - ins->reflection_probe_instances[l++] = reflection_probe->instance; + ins->reflection_probe_instances.write[l++] = reflection_probe->instance; } geom->reflection_dirty = false; @@ -1919,7 +1928,7 @@ void VisualServerScene::_prepare_scene(const Transform p_cam_transform, const Ca InstanceGIProbeData *gi_probe = static_cast<InstanceGIProbeData *>(E->get()->base_data); - ins->gi_probe_instances[l++] = gi_probe->probe_instance; + ins->gi_probe_instances.write[l++] = gi_probe->probe_instance; } geom->gi_probes_dirty = false; @@ -2363,7 +2372,7 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { uint32_t key = blockz * blockw * blockh + blocky * blockw + blockx; - Map<uint32_t, InstanceGIProbeData::CompBlockS3TC> &cmap = comp_blocks[mipmap]; + Map<uint32_t, InstanceGIProbeData::CompBlockS3TC> &cmap = comp_blocks.write[mipmap]; if (!cmap.has(key)) { @@ -2383,8 +2392,8 @@ void VisualServerScene::_setup_gi_probe(Instance *p_instance) { for (int i = 0; i < mipmap_count; i++) { print_line("S3TC level: " + itos(i) + " blocks: " + itos(comp_blocks[i].size())); - probe->dynamic.mipmaps_s3tc[i].resize(comp_blocks[i].size()); - PoolVector<InstanceGIProbeData::CompBlockS3TC>::Write w = probe->dynamic.mipmaps_s3tc[i].write(); + probe->dynamic.mipmaps_s3tc.write[i].resize(comp_blocks[i].size()); + PoolVector<InstanceGIProbeData::CompBlockS3TC>::Write w = probe->dynamic.mipmaps_s3tc.write[i].write(); int block_idx = 0; for (Map<uint32_t, InstanceGIProbeData::CompBlockS3TC>::Element *E = comp_blocks[i].front(); E; E = E->next()) { @@ -2852,7 +2861,7 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { int level_cell_count = probe_data->dynamic.level_cell_lists[i].size(); const uint32_t *level_cells = probe_data->dynamic.level_cell_lists[i].ptr(); - PoolVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d[stage].write(); + PoolVector<uint8_t>::Write lw = probe_data->dynamic.mipmaps_3d.write[stage].write(); uint8_t *mipmapw = lw.ptr(); uint32_t sizes[3] = { header->width >> stage, header->height >> stage, header->depth >> stage }; @@ -2881,7 +2890,7 @@ void VisualServerScene::_bake_gi_probe(Instance *p_gi_probe) { for (int mmi = 0; mmi < mipmap_count; mmi++) { - PoolVector<uint8_t>::Write mmw = probe_data->dynamic.mipmaps_3d[mmi].write(); + PoolVector<uint8_t>::Write mmw = probe_data->dynamic.mipmaps_3d.write[mmi].write(); int block_count = probe_data->dynamic.mipmaps_s3tc[mmi].size(); PoolVector<InstanceGIProbeData::CompBlockS3TC>::Read mmr = probe_data->dynamic.mipmaps_s3tc[mmi].read(); @@ -3214,7 +3223,7 @@ void VisualServerScene::_update_dirty_instance(Instance *p_instance) { if (new_blend_shape_count != p_instance->blend_values.size()) { p_instance->blend_values.resize(new_blend_shape_count); for (int i = 0; i < new_blend_shape_count; i++) { - p_instance->blend_values[i] = 0; + p_instance->blend_values.write[i] = 0; } } } diff --git a/servers/visual/visual_server_viewport.cpp b/servers/visual/visual_server_viewport.cpp index dd6bc3cf26..a700fcf11b 100644 --- a/servers/visual/visual_server_viewport.cpp +++ b/servers/visual/visual_server_viewport.cpp @@ -252,7 +252,9 @@ void VisualServerViewport::draw_viewports() { // process all our active interfaces ARVRServer::get_singleton()->_process(); - clear_color = GLOBAL_GET("rendering/environment/default_clear_color"); + if (Engine::get_singleton()->is_editor_hint()) { + clear_color = GLOBAL_GET("rendering/environment/default_clear_color"); + } //sort viewports active_viewports.sort_custom<ViewportSort>(); @@ -660,5 +662,9 @@ bool VisualServerViewport::free(RID p_rid) { return false; } +void VisualServerViewport::set_default_clear_color(const Color &p_color) { + clear_color = p_color; +} + VisualServerViewport::VisualServerViewport() { } diff --git a/servers/visual/visual_server_viewport.h b/servers/visual/visual_server_viewport.h index c0c83c0450..f915e26b81 100644 --- a/servers/visual/visual_server_viewport.h +++ b/servers/visual/visual_server_viewport.h @@ -188,6 +188,7 @@ public: virtual int viewport_get_render_info(RID p_viewport, VS::ViewportRenderInfo p_info); virtual void viewport_set_debug_draw(RID p_viewport, VS::ViewportDebugDraw p_draw); + void set_default_clear_color(const Color &p_color); void draw_viewports(); bool free(RID p_rid); diff --git a/servers/visual/visual_server_wrap_mt.cpp b/servers/visual/visual_server_wrap_mt.cpp index 094e2794ed..93f3792bdc 100644 --- a/servers/visual/visual_server_wrap_mt.cpp +++ b/servers/visual/visual_server_wrap_mt.cpp @@ -37,11 +37,11 @@ void VisualServerWrapMT::thread_exit() { exit = true; } -void VisualServerWrapMT::thread_draw() { +void VisualServerWrapMT::thread_draw(bool p_swap_buffers, double frame_step) { if (!atomic_decrement(&draw_pending)) { - visual_server->draw(); + visual_server->draw(p_swap_buffers, frame_step); } } @@ -91,15 +91,15 @@ void VisualServerWrapMT::sync() { } } -void VisualServerWrapMT::draw(bool p_swap_buffers) { +void VisualServerWrapMT::draw(bool p_swap_buffers, double frame_step) { if (create_thread) { atomic_increment(&draw_pending); - command_queue.push(this, &VisualServerWrapMT::thread_draw); + command_queue.push(this, &VisualServerWrapMT::thread_draw, p_swap_buffers, frame_step); } else { - visual_server->draw(p_swap_buffers); + visual_server->draw(p_swap_buffers, frame_step); } } diff --git a/servers/visual/visual_server_wrap_mt.h b/servers/visual/visual_server_wrap_mt.h index 48f0ec46f3..3a4d72c793 100644 --- a/servers/visual/visual_server_wrap_mt.h +++ b/servers/visual/visual_server_wrap_mt.h @@ -55,7 +55,7 @@ class VisualServerWrapMT : public VisualServer { bool create_thread; uint64_t draw_pending; - void thread_draw(); + void thread_draw(bool p_swap_buffers, double frame_step); void thread_flush(); void thread_exit(); @@ -82,17 +82,19 @@ public: /* EVENT QUEUING */ FUNCRID(texture) - FUNC5(texture_allocate, RID, int, int, Image::Format, uint32_t) - FUNC3(texture_set_data, RID, const Ref<Image> &, CubeMapSide) - FUNC10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, CubeMapSide) - FUNC2RC(Ref<Image>, texture_get_data, RID, CubeMapSide) + FUNC7(texture_allocate, RID, int, int, int, Image::Format, TextureType, uint32_t) + FUNC3(texture_set_data, RID, const Ref<Image> &, int) + FUNC10(texture_set_data_partial, RID, const Ref<Image> &, int, int, int, int, int, int, int, int) + FUNC2RC(Ref<Image>, texture_get_data, RID, int) FUNC2(texture_set_flags, RID, uint32_t) FUNC1RC(uint32_t, texture_get_flags, RID) FUNC1RC(Image::Format, texture_get_format, RID) + FUNC1RC(TextureType, texture_get_type, RID) FUNC1RC(uint32_t, texture_get_texid, RID) FUNC1RC(uint32_t, texture_get_width, RID) FUNC1RC(uint32_t, texture_get_height, RID) - FUNC3(texture_set_size_override, RID, int, int) + FUNC1RC(uint32_t, texture_get_depth, RID) + FUNC4(texture_set_size_override, RID, int, int, int) FUNC3(texture_set_detect_3d_callback, RID, TextureDetectCallback, void *) FUNC3(texture_set_detect_srgb_callback, RID, TextureDetectCallback, void *) @@ -578,7 +580,7 @@ public: virtual void init(); virtual void finish(); - virtual void draw(bool p_swap_buffers); + virtual void draw(bool p_swap_buffers, double frame_step); virtual void sync(); FUNC0RC(bool, has_changed) diff --git a/servers/visual_server.cpp b/servers/visual_server.cpp index a48f1cccae..bc9e9042ec 100644 --- a/servers/visual_server.cpp +++ b/servers/visual_server.cpp @@ -55,7 +55,7 @@ RID VisualServer::texture_create_from_image(const Ref<Image> &p_image, uint32_t ERR_FAIL_COND_V(!p_image.is_valid(), RID()); RID texture = texture_create(); - texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), p_flags); //if it has mipmaps, use, else generate + texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_flags); //if it has mipmaps, use, else generate ERR_FAIL_COND_V(!texture.is_valid(), texture); texture_set_data(texture, p_image); @@ -72,7 +72,9 @@ Array VisualServer::_texture_debug_usage_bind() { Dictionary dict; dict["texture"] = E->get().texture; - dict["size"] = E->get().size; + dict["width"] = E->get().width; + dict["height"] = E->get().height; + dict["depth"] = E->get().depth; dict["format"] = E->get().format; dict["bytes"] = E->get().bytes; dict["path"] = E->get().path; @@ -187,16 +189,14 @@ RID VisualServer::_make_test_cube() { PoolVector<float> tangents; PoolVector<Vector3> uvs; - int vtx_idx = 0; -#define ADD_VTX(m_idx) \ - vertices.push_back(face_points[m_idx]); \ - normals.push_back(normal_points[m_idx]); \ - tangents.push_back(normal_points[m_idx][1]); \ - tangents.push_back(normal_points[m_idx][2]); \ - tangents.push_back(normal_points[m_idx][0]); \ - tangents.push_back(1.0); \ - uvs.push_back(Vector3(uv_points[m_idx * 2 + 0], uv_points[m_idx * 2 + 1], 0)); \ - vtx_idx++; +#define ADD_VTX(m_idx) \ + vertices.push_back(face_points[m_idx]); \ + normals.push_back(normal_points[m_idx]); \ + tangents.push_back(normal_points[m_idx][1]); \ + tangents.push_back(normal_points[m_idx][2]); \ + tangents.push_back(normal_points[m_idx][0]); \ + tangents.push_back(1.0); \ + uvs.push_back(Vector3(uv_points[m_idx * 2 + 0], uv_points[m_idx * 2 + 1], 0)); for (int i = 0; i < 6; i++) { @@ -335,7 +335,7 @@ RID VisualServer::get_white_texture() { } Ref<Image> white = memnew(Image(4, 4, 0, Image::FORMAT_RGB8, wt)); white_texture = texture_create(); - texture_allocate(white_texture, 4, 4, Image::FORMAT_RGB8); + texture_allocate(white_texture, 4, 4, 0, Image::FORMAT_RGB8, TEXTURE_TYPE_2D); texture_set_data(white_texture, white); return white_texture; } @@ -746,7 +746,7 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ if (first) { for (int i = 0; i < total_bones; i++) { - r_bone_aabb[i].size = Vector3(-1, -1, -1); //negative means unused + r_bone_aabb.write[i].size = Vector3(-1, -1, -1); //negative means unused } } @@ -795,6 +795,140 @@ Error VisualServer::_surface_set_data(Array p_arrays, uint32_t p_format, uint32_ return OK; } +uint32_t VisualServer::mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const { + uint32_t offsets[ARRAY_MAX]; + mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets); + return offsets[p_array_index]; +} + +uint32_t VisualServer::mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const { + uint32_t offsets[ARRAY_MAX]; + return mesh_surface_make_offsets_from_format(p_format, p_vertex_len, p_index_len, offsets); +} + +uint32_t VisualServer::mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const { + + int total_elem_size = 0; + + for (int i = 0; i < VS::ARRAY_MAX; i++) { + + r_offsets[i] = 0; //reset + + if (!(p_format & (1 << i))) // no array + continue; + + int elem_size = 0; + + switch (i) { + + case VS::ARRAY_VERTEX: { + + if (p_format & ARRAY_FLAG_USE_2D_VERTICES) { + elem_size = 2; + } else { + elem_size = 3; + } + + if (p_format & ARRAY_COMPRESS_VERTEX) { + elem_size *= sizeof(int16_t); + } else { + elem_size *= sizeof(float); + } + + if (elem_size == 6) { + elem_size = 8; + } + + } break; + case VS::ARRAY_NORMAL: { + + if (p_format & ARRAY_COMPRESS_NORMAL) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 3; + } + + } break; + + case VS::ARRAY_TANGENT: { + if (p_format & ARRAY_COMPRESS_TANGENT) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 4; + } + + } break; + case VS::ARRAY_COLOR: { + + if (p_format & ARRAY_COMPRESS_COLOR) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 4; + } + } break; + case VS::ARRAY_TEX_UV: { + if (p_format & ARRAY_COMPRESS_TEX_UV) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 2; + } + + } break; + + case VS::ARRAY_TEX_UV2: { + if (p_format & ARRAY_COMPRESS_TEX_UV2) { + elem_size = sizeof(uint32_t); + } else { + elem_size = sizeof(float) * 2; + } + + } break; + case VS::ARRAY_WEIGHTS: { + + if (p_format & ARRAY_COMPRESS_WEIGHTS) { + elem_size = sizeof(uint16_t) * 4; + } else { + elem_size = sizeof(float) * 4; + } + + } break; + case VS::ARRAY_BONES: { + + if (p_format & ARRAY_FLAG_USE_16_BIT_BONES) { + elem_size = sizeof(uint16_t) * 4; + } else { + elem_size = sizeof(uint32_t); + } + + } break; + case VS::ARRAY_INDEX: { + + if (p_index_len <= 0) { + ERR_PRINT("index_array_len==NO_INDEX_ARRAY"); + break; + } + /* determine whether using 16 or 32 bits indices */ + if (p_vertex_len >= (1 << 16)) { + + elem_size = 4; + + } else { + elem_size = 2; + } + r_offsets[i] = elem_size; + continue; + } break; + default: { + ERR_FAIL_V(0); + } + } + + r_offsets[i] = total_elem_size; + total_elem_size += elem_size; + } + return total_elem_size; +} + void VisualServer::mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes, uint32_t p_compress_format) { ERR_FAIL_INDEX(p_primitive, VS::PRIMITIVE_MAX); @@ -1516,27 +1650,29 @@ Array VisualServer::_mesh_surface_get_skeleton_aabb_bind(RID p_mesh, int p_surfa void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("force_sync"), &VisualServer::sync); - ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers"), &VisualServer::draw, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("force_draw", "swap_buffers", "frame_step"), &VisualServer::draw, DEFVAL(true), DEFVAL(0.0)); // "draw" and "sync" are deprecated duplicates of "force_draw" and "force_sync" // FIXME: Add deprecation messages using GH-4397 once available, and retire // once the warnings have been enabled for a full release cycle ClassDB::bind_method(D_METHOD("sync"), &VisualServer::sync); - ClassDB::bind_method(D_METHOD("draw", "swap_buffers"), &VisualServer::draw, DEFVAL(true)); + ClassDB::bind_method(D_METHOD("draw", "swap_buffers", "frame_step"), &VisualServer::draw, DEFVAL(true), DEFVAL(0.0)); ClassDB::bind_method(D_METHOD("texture_create"), &VisualServer::texture_create); ClassDB::bind_method(D_METHOD("texture_create_from_image", "image", "flags"), &VisualServer::texture_create_from_image, DEFVAL(TEXTURE_FLAGS_DEFAULT)); - ClassDB::bind_method(D_METHOD("texture_allocate", "texture", "width", "height", "format", "flags"), &VisualServer::texture_allocate, DEFVAL(TEXTURE_FLAGS_DEFAULT)); - ClassDB::bind_method(D_METHOD("texture_set_data", "texture", "image", "cube_side"), &VisualServer::texture_set_data, DEFVAL(CUBEMAP_LEFT)); - ClassDB::bind_method(D_METHOD("texture_set_data_partial", "texture", "image", "src_x", "src_y", "src_w", "src_h", "dst_x", "dst_y", "dst_mip", "cube_side"), &VisualServer::texture_set_data_partial, DEFVAL(CUBEMAP_LEFT)); + ClassDB::bind_method(D_METHOD("texture_allocate", "texture", "width", "height", "depth_3d", "format", "type", "flags"), &VisualServer::texture_allocate, DEFVAL(TEXTURE_FLAGS_DEFAULT)); + ClassDB::bind_method(D_METHOD("texture_set_data", "texture", "image", "layer"), &VisualServer::texture_set_data, DEFVAL(0)); + ClassDB::bind_method(D_METHOD("texture_set_data_partial", "texture", "image", "src_x", "src_y", "src_w", "src_h", "dst_x", "dst_y", "dst_mip", "layer"), &VisualServer::texture_set_data_partial, DEFVAL(0)); ClassDB::bind_method(D_METHOD("texture_get_data", "texture", "cube_side"), &VisualServer::texture_get_data, DEFVAL(CUBEMAP_LEFT)); ClassDB::bind_method(D_METHOD("texture_set_flags", "texture", "flags"), &VisualServer::texture_set_flags); ClassDB::bind_method(D_METHOD("texture_get_flags", "texture"), &VisualServer::texture_get_flags); ClassDB::bind_method(D_METHOD("texture_get_format", "texture"), &VisualServer::texture_get_format); + ClassDB::bind_method(D_METHOD("texture_get_type", "texture"), &VisualServer::texture_get_type); ClassDB::bind_method(D_METHOD("texture_get_texid", "texture"), &VisualServer::texture_get_texid); ClassDB::bind_method(D_METHOD("texture_get_width", "texture"), &VisualServer::texture_get_width); ClassDB::bind_method(D_METHOD("texture_get_height", "texture"), &VisualServer::texture_get_height); - ClassDB::bind_method(D_METHOD("texture_set_size_override", "texture", "width", "height"), &VisualServer::texture_set_size_override); + ClassDB::bind_method(D_METHOD("texture_get_depth", "texture"), &VisualServer::texture_get_depth); + ClassDB::bind_method(D_METHOD("texture_set_size_override", "texture", "width", "height", "depth"), &VisualServer::texture_set_size_override); ClassDB::bind_method(D_METHOD("texture_set_path", "texture", "path"), &VisualServer::texture_set_path); ClassDB::bind_method(D_METHOD("texture_get_path", "texture"), &VisualServer::texture_get_path); ClassDB::bind_method(D_METHOD("texture_set_shrink_all_x2_on_set_data", "shrink"), &VisualServer::texture_set_shrink_all_x2_on_set_data); @@ -1564,11 +1700,14 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("material_set_next_pass", "material", "next_material"), &VisualServer::material_set_next_pass); ClassDB::bind_method(D_METHOD("mesh_create"), &VisualServer::mesh_create); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_offset", "format", "vertex_len", "index_len", "array_index"), &VisualServer::mesh_surface_get_format_offset); + ClassDB::bind_method(D_METHOD("mesh_surface_get_format_stride", "format", "vertex_len", "index_len"), &VisualServer::mesh_surface_get_format_stride); ClassDB::bind_method(D_METHOD("mesh_add_surface_from_arrays", "mesh", "primtive", "arrays", "blend_shapes", "compress_format"), &VisualServer::mesh_add_surface_from_arrays, DEFVAL(Array()), DEFVAL(ARRAY_COMPRESS_DEFAULT)); ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_count", "mesh", "amount"), &VisualServer::mesh_set_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_count", "mesh"), &VisualServer::mesh_get_blend_shape_count); ClassDB::bind_method(D_METHOD("mesh_set_blend_shape_mode", "mesh", "mode"), &VisualServer::mesh_set_blend_shape_mode); ClassDB::bind_method(D_METHOD("mesh_get_blend_shape_mode", "mesh"), &VisualServer::mesh_get_blend_shape_mode); + ClassDB::bind_method(D_METHOD("mesh_surface_update_region", "mesh", "surface", "offset", "data"), &VisualServer::mesh_surface_update_region); ClassDB::bind_method(D_METHOD("mesh_surface_set_material", "mesh", "surface", "material"), &VisualServer::mesh_surface_set_material); ClassDB::bind_method(D_METHOD("mesh_surface_get_material", "mesh", "surface"), &VisualServer::mesh_surface_get_material); ClassDB::bind_method(D_METHOD("mesh_surface_get_array_len", "mesh", "surface"), &VisualServer::mesh_surface_get_array_len); @@ -1773,7 +1912,7 @@ void VisualServer::_bind_methods() { ClassDB::bind_method(D_METHOD("environment_set_tonemap", "env", "tone_mapper", "exposure", "white", "auto_exposure", "min_luminance", "max_luminance", "auto_exp_speed", "auto_exp_grey"), &VisualServer::environment_set_tonemap); ClassDB::bind_method(D_METHOD("environment_set_adjustment", "env", "enable", "brightness", "contrast", "saturation", "ramp"), &VisualServer::environment_set_adjustment); ClassDB::bind_method(D_METHOD("environment_set_ssr", "env", "enable", "max_steps", "fade_in", "fade_out", "depth_tolerance", "roughness"), &VisualServer::environment_set_ssr); - ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "radius2", "intensity2", "bias", "light_affect", "color", "quality", "blur", "bilateral_sharpness"), &VisualServer::environment_set_ssao); + ClassDB::bind_method(D_METHOD("environment_set_ssao", "env", "enable", "radius", "intensity", "radius2", "intensity2", "bias", "light_affect", "ao_channel_affect", "color", "quality", "blur", "bilateral_sharpness"), &VisualServer::environment_set_ssao); ClassDB::bind_method(D_METHOD("environment_set_fog", "env", "enable", "color", "sun_color", "sun_amount"), &VisualServer::environment_set_fog); ClassDB::bind_method(D_METHOD("environment_set_fog_depth", "env", "enable", "depth_begin", "depth_curve", "transmit", "transmit_curve"), &VisualServer::environment_set_fog_depth); ClassDB::bind_method(D_METHOD("environment_set_fog_height", "env", "enable", "min_height", "max_height", "height_curve"), &VisualServer::environment_set_fog_height); @@ -1924,13 +2063,17 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(CUBEMAP_FRONT); BIND_ENUM_CONSTANT(CUBEMAP_BACK); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_CUBEMAP); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_2D_ARRAY); + BIND_ENUM_CONSTANT(TEXTURE_TYPE_3D); + BIND_ENUM_CONSTANT(TEXTURE_FLAG_MIPMAPS); BIND_ENUM_CONSTANT(TEXTURE_FLAG_REPEAT); BIND_ENUM_CONSTANT(TEXTURE_FLAG_FILTER); BIND_ENUM_CONSTANT(TEXTURE_FLAG_ANISOTROPIC_FILTER); BIND_ENUM_CONSTANT(TEXTURE_FLAG_CONVERT_TO_LINEAR); BIND_ENUM_CONSTANT(TEXTURE_FLAG_MIRRORED_REPEAT); - BIND_ENUM_CONSTANT(TEXTURE_FLAG_CUBEMAP); BIND_ENUM_CONSTANT(TEXTURE_FLAG_USED_FOR_STREAMING); BIND_ENUM_CONSTANT(TEXTURE_FLAGS_DEFAULT); @@ -2066,6 +2209,7 @@ void VisualServer::_bind_methods() { BIND_ENUM_CONSTANT(INSTANCE_GEOMETRY_MASK); BIND_ENUM_CONSTANT(INSTANCE_FLAG_USE_BAKED_LIGHT); + BIND_ENUM_CONSTANT(INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE); BIND_ENUM_CONSTANT(INSTANCE_FLAG_MAX); BIND_ENUM_CONSTANT(SHADOW_CASTING_SETTING_OFF); diff --git a/servers/visual_server.h b/servers/visual_server.h index 968cb852ed..0ec902c18c 100644 --- a/servers/visual_server.h +++ b/servers/visual_server.h @@ -90,11 +90,17 @@ public: TEXTURE_FLAG_ANISOTROPIC_FILTER = 8, TEXTURE_FLAG_CONVERT_TO_LINEAR = 16, TEXTURE_FLAG_MIRRORED_REPEAT = 32, /// Repeat texture, with alternate sections mirrored - TEXTURE_FLAG_CUBEMAP = 2048, - TEXTURE_FLAG_USED_FOR_STREAMING = 4096, + TEXTURE_FLAG_USED_FOR_STREAMING = 2048, TEXTURE_FLAGS_DEFAULT = TEXTURE_FLAG_REPEAT | TEXTURE_FLAG_MIPMAPS | TEXTURE_FLAG_FILTER }; + enum TextureType { + TEXTURE_TYPE_2D, + TEXTURE_TYPE_CUBEMAP, + TEXTURE_TYPE_2D_ARRAY, + TEXTURE_TYPE_3D, + }; + enum CubeMapSide { CUBEMAP_LEFT, @@ -107,17 +113,33 @@ public: virtual RID texture_create() = 0; RID texture_create_from_image(const Ref<Image> &p_image, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT); // helper - virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = TEXTURE_FLAGS_DEFAULT) = 0; - virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, CubeMapSide p_cube_side = CUBEMAP_LEFT) = 0; - virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, CubeMapSide p_cube_side = CUBEMAP_LEFT) = 0; - virtual Ref<Image> texture_get_data(RID p_texture, CubeMapSide p_cube_side = CUBEMAP_LEFT) const = 0; + virtual void texture_allocate(RID p_texture, + int p_width, + int p_height, + int p_depth_3d, + Image::Format p_format, + TextureType p_type, + uint32_t p_flags = TEXTURE_FLAGS_DEFAULT) = 0; + + virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0) = 0; + virtual void texture_set_data_partial(RID p_texture, + const Ref<Image> &p_image, + int src_x, int src_y, + int src_w, int src_h, + int dst_x, int dst_y, + int p_dst_mip, + int p_layer = 0) = 0; + + virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const = 0; virtual void texture_set_flags(RID p_texture, uint32_t p_flags) = 0; virtual uint32_t texture_get_flags(RID p_texture) const = 0; virtual Image::Format texture_get_format(RID p_texture) const = 0; + virtual TextureType texture_get_type(RID p_texture) const = 0; virtual uint32_t texture_get_texid(RID p_texture) const = 0; virtual uint32_t texture_get_width(RID p_texture) const = 0; virtual uint32_t texture_get_height(RID p_texture) const = 0; - virtual void texture_set_size_override(RID p_texture, int p_width, int p_height) = 0; + virtual uint32_t texture_get_depth(RID p_texture) const = 0; + virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) = 0; virtual void texture_set_path(RID p_texture, const String &p_path) = 0; virtual String texture_get_path(RID p_texture) const = 0; @@ -132,7 +154,9 @@ public: struct TextureInfo { RID texture; - Size2 size; + uint32_t width; + uint32_t height; + uint32_t depth; Image::Format format; int bytes; String path; @@ -251,6 +275,10 @@ public: virtual RID mesh_create() = 0; + virtual uint32_t mesh_surface_get_format_offset(uint32_t p_format, int p_vertex_len, int p_index_len, int p_array_index) const; + virtual uint32_t mesh_surface_get_format_stride(uint32_t p_format, int p_vertex_len, int p_index_len) const; + /// Returns stride + virtual uint32_t mesh_surface_make_offsets_from_format(uint32_t p_format, int p_vertex_len, int p_index_len, uint32_t *r_offsets) const; virtual void mesh_add_surface_from_arrays(RID p_mesh, PrimitiveType p_primitive, const Array &p_arrays, const Array &p_blend_shapes = Array(), uint32_t p_compress_format = ARRAY_COMPRESS_DEFAULT); virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, PrimitiveType p_primitive, const PoolVector<uint8_t> &p_array, int p_vertex_count, const PoolVector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<PoolVector<uint8_t> > &p_blend_shapes = Vector<PoolVector<uint8_t> >(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>()) = 0; @@ -805,6 +833,7 @@ public: enum InstanceFlags { INSTANCE_FLAG_USE_BAKED_LIGHT, + INSTANCE_FLAG_DRAW_NEXT_FRAME_IF_VISIBLE, INSTANCE_FLAG_MAX }; @@ -950,7 +979,7 @@ public: /* EVENT QUEUING */ - virtual void draw(bool p_swap_buffers = true) = 0; + virtual void draw(bool p_swap_buffers = true, double frame_step = 0.0) = 0; virtual void sync() = 0; virtual bool has_changed() const = 0; virtual void init() = 0; @@ -1049,6 +1078,7 @@ VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOQuality); VARIANT_ENUM_CAST(VisualServer::EnvironmentSSAOBlur); VARIANT_ENUM_CAST(VisualServer::InstanceFlags); VARIANT_ENUM_CAST(VisualServer::ShadowCastingSetting); +VARIANT_ENUM_CAST(VisualServer::TextureType); //typedef VisualServer VS; // makes it easier to use #define VS VisualServer |