diff options
Diffstat (limited to 'drivers')
120 files changed, 5486 insertions, 4184 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index f9cfa3fb05..320d4dc4bb 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -4,9 +4,6 @@ Import('env') env.drivers_sources = [] -if 'builtin_zlib' in env and env['builtin_zlib']: - SConscript("zlib/SCsub") - # OS drivers SConscript('unix/SCsub') SConscript('windows/SCsub') diff --git a/drivers/alsa/SCsub b/drivers/alsa/SCsub index ee39fd2631..28b315ae66 100644 --- a/drivers/alsa/SCsub +++ b/drivers/alsa/SCsub @@ -3,5 +3,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 1f53d52951..50697b8834 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -32,8 +32,8 @@ #ifdef ALSA_ENABLED -#include "os/os.h" -#include "project_settings.h" +#include "core/os/os.h" +#include "core/project_settings.h" #include <errno.h> diff --git a/drivers/alsamidi/SCsub b/drivers/alsamidi/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/alsamidi/SCsub +++ b/drivers/alsamidi/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/alsamidi/alsa_midi.cpp b/drivers/alsamidi/alsa_midi.cpp index 599470d7e0..33ad7e3f17 100644 --- a/drivers/alsamidi/alsa_midi.cpp +++ b/drivers/alsamidi/alsa_midi.cpp @@ -30,11 +30,12 @@ #ifdef ALSAMIDI_ENABLED -#include <errno.h> - #include "alsa_midi.h" -#include "os/os.h" -#include "print_string.h" + +#include "core/os/os.h" +#include "core/print_string.h" + +#include <errno.h> static int get_message_size(uint8_t message) { switch (message & 0xF0) { diff --git a/drivers/alsamidi/alsa_midi.h b/drivers/alsamidi/alsa_midi.h index 90e458a365..5741036166 100644 --- a/drivers/alsamidi/alsa_midi.h +++ b/drivers/alsamidi/alsa_midi.h @@ -33,13 +33,13 @@ #ifndef ALSA_MIDI_H #define ALSA_MIDI_H -#include <alsa/asoundlib.h> -#include <stdio.h> - +#include "core/os/midi_driver.h" #include "core/os/mutex.h" #include "core/os/thread.h" #include "core/vector.h" -#include "os/midi_driver.h" + +#include <alsa/asoundlib.h> +#include <stdio.h> class MIDIDriverALSAMidi : public MIDIDriver { diff --git a/drivers/convex_decomp/SCsub b/drivers/convex_decomp/SCsub index f017e55120..65ba5332b7 100644 --- a/drivers/convex_decomp/SCsub +++ b/drivers/convex_decomp/SCsub @@ -11,6 +11,7 @@ thirdparty_sources = [ "b2Triangle.cpp", ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env.add_source_files(env.drivers_sources, thirdparty_sources) -Export('env') +env_thirdparty = env.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) diff --git a/drivers/convex_decomp/b2d_decompose.h b/drivers/convex_decomp/b2d_decompose.h index b21792047e..f6b08b957c 100644 --- a/drivers/convex_decomp/b2d_decompose.h +++ b/drivers/convex_decomp/b2d_decompose.h @@ -31,8 +31,9 @@ #ifndef B2D_DECOMPOSE_H #define B2D_DECOMPOSE_H -#include "vector.h" -#include "vector2.h" +#include "core/math/vector2.h" +#include "core/vector.h" + Vector<Vector<Vector2> > b2d_decompose(const Vector<Vector2> &p_polygon); #endif // B2D_DECOMPOSE_H diff --git a/drivers/coreaudio/SCsub b/drivers/coreaudio/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/coreaudio/SCsub +++ b/drivers/coreaudio/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 45d62e797f..850b90d59b 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -31,8 +31,9 @@ #ifdef COREAUDIO_ENABLED #include "audio_driver_coreaudio.h" + +#include "core/os/os.h" #include "core/project_settings.h" -#include "os/os.h" #define kOutputBus 0 #define kInputBus 1 @@ -94,11 +95,6 @@ Error AudioDriverCoreAudio::init() { result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); ERR_FAIL_COND_V(result != noErr, FAILED); - - prop.mSelector = kAudioHardwarePropertyDefaultInputDevice; - - result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); - ERR_FAIL_COND_V(result != noErr, FAILED); #endif AudioStreamBasicDescription strdesc; @@ -122,26 +118,6 @@ Error AudioDriverCoreAudio::init() { break; } - zeromem(&strdesc, sizeof(strdesc)); - size = sizeof(strdesc); - result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size); - ERR_FAIL_COND_V(result != noErr, FAILED); - - switch (strdesc.mChannelsPerFrame) { - case 1: // Mono - capture_channels = 1; - break; - - case 2: // Stereo - capture_channels = 2; - break; - - default: - // Unknown number of channels, default to stereo - capture_channels = 2; - break; - } - mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); zeromem(&strdesc, sizeof(strdesc)); @@ -157,11 +133,6 @@ Error AudioDriverCoreAudio::init() { result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc)); ERR_FAIL_COND_V(result != noErr, FAILED); - strdesc.mChannelsPerFrame = capture_channels; - - result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc)); - ERR_FAIL_COND_V(result != noErr, FAILED); - int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) buffer_frames = closest_power_of_2(latency * mix_rate / 1000); @@ -174,9 +145,6 @@ Error AudioDriverCoreAudio::init() { unsigned int buffer_size = buffer_frames * channels; samples_in.resize(buffer_size); input_buf.resize(buffer_size); - input_buffer.resize(buffer_size * 8); - input_position = 0; - input_size = 0; print_verbose("CoreAudio: detected " + itos(channels) + " channels"); print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); @@ -188,16 +156,10 @@ Error AudioDriverCoreAudio::init() { result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); ERR_FAIL_COND_V(result != noErr, FAILED); - zeromem(&callback, sizeof(AURenderCallbackStruct)); - callback.inputProc = &AudioDriverCoreAudio::input_callback; - callback.inputProcRefCon = this; - result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback)); - ERR_FAIL_COND_V(result != noErr, FAILED); - result = AudioUnitInitialize(audio_unit); ERR_FAIL_COND_V(result != noErr, FAILED); - return OK; + return capture_init(); } OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon, @@ -264,7 +226,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, bufferList.mBuffers[0].mNumberChannels = ad->capture_channels; bufferList.mBuffers[0].mDataByteSize = ad->input_buf.size() * sizeof(int16_t); - OSStatus result = AudioUnitRender(ad->audio_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList); + OSStatus result = AudioUnitRender(ad->input_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList); if (result == noErr) { for (int i = 0; i < inNumberFrames * ad->capture_channels; i++) { int32_t sample = ad->input_buf[i] << 16; @@ -276,7 +238,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, } } } else { - ERR_PRINT(("AudioUnitRender failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioUnitRender failed, code: " + itos(result)); } ad->unlock(); @@ -288,7 +250,7 @@ void AudioDriverCoreAudio::start() { if (!active) { OSStatus result = AudioOutputUnitStart(audio_unit); if (result != noErr) { - ERR_PRINT(("AudioOutputUnitStart failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result)); } else { active = true; } @@ -299,7 +261,7 @@ void AudioDriverCoreAudio::stop() { if (active) { OSStatus result = AudioOutputUnitStop(audio_unit); if (result != noErr) { - ERR_PRINT(("AudioOutputUnitStop failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result)); } else { active = false; } @@ -331,6 +293,8 @@ bool AudioDriverCoreAudio::try_lock() { } void AudioDriverCoreAudio::finish() { + capture_finish(); + if (audio_unit) { OSStatus result; @@ -374,6 +338,7 @@ void AudioDriverCoreAudio::finish() { ERR_PRINT("AudioComponentInstanceDispose failed"); } + audio_unit = NULL; unlock(); } @@ -383,20 +348,160 @@ void AudioDriverCoreAudio::finish() { } } -Error AudioDriverCoreAudio::capture_start() { +Error AudioDriverCoreAudio::capture_init() { + AudioComponentDescription desc; + zeromem(&desc, sizeof(desc)); + desc.componentType = kAudioUnitType_Output; +#ifdef OSX_ENABLED + desc.componentSubType = kAudioUnitSubType_HALOutput; +#else + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#endif + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + + AudioComponent comp = AudioComponentFindNext(NULL, &desc); + ERR_FAIL_COND_V(comp == NULL, FAILED); + + OSStatus result = AudioComponentInstanceNew(comp, &input_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + +#ifdef OSX_ENABLED + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultInputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; + + result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); + ERR_FAIL_COND_V(result != noErr, FAILED); +#endif UInt32 flag = 1; - OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); + result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); + ERR_FAIL_COND_V(result != noErr, FAILED); + flag = 0; + result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + UInt32 size; +#ifdef OSX_ENABLED + AudioDeviceID deviceId; + size = sizeof(AudioDeviceID); + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; + + result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId); + ERR_FAIL_COND_V(result != noErr, FAILED); + + result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID)); + ERR_FAIL_COND_V(result != noErr, FAILED); +#endif + + AudioStreamBasicDescription strdesc; + zeromem(&strdesc, sizeof(strdesc)); + size = sizeof(strdesc); + result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size); + ERR_FAIL_COND_V(result != noErr, FAILED); + + switch (strdesc.mChannelsPerFrame) { + case 1: // Mono + capture_channels = 1; + break; + + case 2: // Stereo + capture_channels = 2; + break; + + default: + // Unknown number of channels, default to stereo + capture_channels = 2; + break; + } + + mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); + + zeromem(&strdesc, sizeof(strdesc)); + strdesc.mFormatID = kAudioFormatLinearPCM; + strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; + strdesc.mChannelsPerFrame = capture_channels; + strdesc.mSampleRate = mix_rate; + strdesc.mFramesPerPacket = 1; + strdesc.mBitsPerChannel = 16; + strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8; + strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; + + result = AudioUnitSetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + callback.inputProc = &AudioDriverCoreAudio::input_callback; + callback.inputProcRefCon = this; + result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + result = AudioUnitInitialize(input_unit); ERR_FAIL_COND_V(result != noErr, FAILED); return OK; } +void AudioDriverCoreAudio::capture_finish() { + if (input_unit) { + lock(); + + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + OSStatus result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback)); + if (result != noErr) { + ERR_PRINT("AudioUnitSetProperty failed"); + } + + result = AudioUnitUninitialize(input_unit); + if (result != noErr) { + ERR_PRINT("AudioUnitUninitialize failed"); + } + +#ifdef OSX_ENABLED + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultInputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; + + result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); + if (result != noErr) { + ERR_PRINT("AudioObjectRemovePropertyListener failed"); + } +#endif + + result = AudioComponentInstanceDispose(input_unit); + if (result != noErr) { + ERR_PRINT("AudioComponentInstanceDispose failed"); + } + + input_unit = NULL; + unlock(); + } +} + +Error AudioDriverCoreAudio::capture_start() { + + input_buffer_init(buffer_frames); + + OSStatus result = AudioOutputUnitStart(input_unit); + if (result != noErr) { + ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result)); + } + + return OK; +} + Error AudioDriverCoreAudio::capture_stop() { - UInt32 flag = 0; - OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); - ERR_FAIL_COND_V(result != noErr, FAILED); + if (input_unit) { + OSStatus result = AudioOutputUnitStop(input_unit); + if (result != noErr) { + ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result)); + } + } return OK; } @@ -530,12 +635,14 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { } if (found) { - OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, capture ? kInputBus : kOutputBus, &deviceId, sizeof(AudioDeviceID)); + OSStatus result = AudioUnitSetProperty(capture ? input_unit : audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID)); ERR_FAIL_COND(result != noErr); - // Reset audio input to keep synchronisation. - input_position = 0; - input_size = 0; + if (capture) { + // Reset audio input to keep synchronisation. + input_position = 0; + input_size = 0; + } } } @@ -579,6 +686,7 @@ String AudioDriverCoreAudio::capture_get_device() { AudioDriverCoreAudio::AudioDriverCoreAudio() { audio_unit = NULL; + input_unit = NULL; active = false; mutex = NULL; diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index d3f7c8d596..474a9e43ae 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -43,6 +43,7 @@ class AudioDriverCoreAudio : public AudioDriver { AudioComponentInstance audio_unit; + AudioComponentInstance input_unit; bool active; Mutex *mutex; @@ -83,6 +84,9 @@ class AudioDriverCoreAudio : public AudioDriver { UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + Error capture_init(); + void capture_finish(); + public: const char *get_name() const { return "CoreAudio"; diff --git a/drivers/coremidi/SCsub b/drivers/coremidi/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/coremidi/SCsub +++ b/drivers/coremidi/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/coremidi/core_midi.cpp b/drivers/coremidi/core_midi.cpp index 6d4624e05b..2ebbabaa38 100644 --- a/drivers/coremidi/core_midi.cpp +++ b/drivers/coremidi/core_midi.cpp @@ -31,7 +31,8 @@ #ifdef COREMIDI_ENABLED #include "core_midi.h" -#include "print_string.h" + +#include "core/print_string.h" #include <CoreAudio/HostTime.h> #include <CoreServices/CoreServices.h> @@ -50,13 +51,13 @@ Error MIDIDriverCoreMidi::open() { OSStatus result = MIDIClientCreate(name, NULL, NULL, &client); CFRelease(name); if (result != noErr) { - ERR_PRINTS("MIDIClientCreate failed: " + String(GetMacOSStatusErrorString(result))); + ERR_PRINTS("MIDIClientCreate failed, code: " + itos(result)); return ERR_CANT_OPEN; } result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in); if (result != noErr) { - ERR_PRINTS("MIDIInputPortCreate failed: " + String(GetMacOSStatusErrorString(result))); + ERR_PRINTS("MIDIInputPortCreate failed, code: " + itos(result)); return ERR_CANT_OPEN; } @@ -64,7 +65,7 @@ Error MIDIDriverCoreMidi::open() { for (int i = 0; i < sources; i++) { MIDIEndpointRef source = MIDIGetSource(i); - if (source != NULL) { + if (source) { MIDIPortConnectSource(port_in, source, (void *)this); connected_sources.insert(i, source); } diff --git a/drivers/coremidi/core_midi.h b/drivers/coremidi/core_midi.h index c6b443764f..ea6b0fcb06 100644 --- a/drivers/coremidi/core_midi.h +++ b/drivers/coremidi/core_midi.h @@ -33,12 +33,11 @@ #ifndef CORE_MIDI_H #define CORE_MIDI_H -#include <stdio.h> +#include "core/os/midi_driver.h" +#include "core/vector.h" #include <CoreMIDI/CoreMIDI.h> - -#include "core/vector.h" -#include "os/midi_driver.h" +#include <stdio.h> class MIDIDriverCoreMidi : public MIDIDriver { diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 0381d3f0c1..d109ef7b91 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -27,16 +27,16 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RASTERIZER_DUMMY_H #define RASTERIZER_DUMMY_H -#include "camera_matrix.h" +#include "core/math/camera_matrix.h" +#include "core/self_list.h" #include "scene/resources/mesh.h" #include "servers/visual/rasterizer.h" #include "servers/visual_server.h" -#include "self_list.h" - class RasterizerSceneDummy : public RasterizerScene { public: /* SHADOW ATLAS API */ @@ -267,6 +267,7 @@ public: void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {} Variant material_get_param(RID p_material, const StringName &p_param) const { return Variant(); } + Variant material_get_param_default(RID p_material, const StringName &p_param) const { return Variant(); } void material_set_line_width(RID p_material, float p_width) {} @@ -516,6 +517,7 @@ public: void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {} void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {} void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {} + void reflection_probe_set_resolution(RID p_probe, int p_resolution) {} AABB reflection_probe_get_aabb(RID p_probe) const { return AABB(); } VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return VisualServer::REFLECTION_PROBE_UPDATE_ONCE; } @@ -786,6 +788,7 @@ public: void restore_render_target() {} void clear_render_target(const Color &p_color) {} void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) {} + void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {} void end_frame(bool p_swap_buffers) {} void finalize() {} @@ -801,6 +804,8 @@ public: _create_func = _create_current; } + virtual bool is_low_end() const { return true; } + RasterizerDummy() {} ~RasterizerDummy() {} }; diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp index b099019d17..8153fbd10b 100644 --- a/drivers/dummy/texture_loader_dummy.cpp +++ b/drivers/dummy/texture_loader_dummy.cpp @@ -29,8 +29,10 @@ /*************************************************************************/ #include "texture_loader_dummy.h" + #include "core/os/file_access.h" -#include "print_string.h" +#include "core/print_string.h" + #include <string.h> RES ResourceFormatDummyTexture::load(const String &p_path, const String &p_original_path, Error *r_error) { diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub index 4d66a9f9f1..efb26a7908 100644 --- a/drivers/gl_context/SCsub +++ b/drivers/gl_context/SCsub @@ -10,13 +10,14 @@ if (env["platform"] in ["haiku", "osx", "windows", "x11"]): ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - env.add_source_files(env.drivers_sources, thirdparty_sources) env.Append(CPPPATH=[thirdparty_dir]) env.Append(CPPFLAGS=['-DGLAD_ENABLED']) env.Append(CPPFLAGS=['-DGLES_OVER_GL']) + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) + # Godot source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/gl_context/context_gl.h b/drivers/gl_context/context_gl.h index 60781a3453..37f334454b 100644 --- a/drivers/gl_context/context_gl.h +++ b/drivers/gl_context/context_gl.h @@ -33,7 +33,7 @@ #if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) -#include "typedefs.h" +#include "core/typedefs.h" /** @author Juan Linietsky <reduzio@gmail.com> diff --git a/drivers/gles2/SCsub b/drivers/gles2/SCsub index 2471dd3739..9923e52c73 100644 --- a/drivers/gles2/SCsub +++ b/drivers/gles2/SCsub @@ -2,6 +2,6 @@ Import('env') -env.add_source_files(env.drivers_sources,"*.cpp") +env.add_source_files(env.drivers_sources, "*.cpp") SConscript("shaders/SCsub") diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 9a9ede761a..9227c04e71 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -27,11 +27,14 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "rasterizer_canvas_gles2.h" -#include "os/os.h" -#include "project_settings.h" + +#include "core/os/os.h" +#include "core/project_settings.h" #include "rasterizer_scene_gles2.h" #include "servers/visual/visual_server_raster.h" + #ifndef GLES_OVER_GL #define glClearDepth glClearDepthf #endif @@ -562,7 +565,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur buffer[(1 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x; buffer[(1 * 4 * 4) + 15] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y; - // thrid row + // third row buffer[(2 * 4 * 4) + 0] = np->rect.position.x; buffer[(2 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM]; @@ -808,8 +811,6 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons bool rebind_shader = true; - Size2 rt_size = Size2(storage->frame.current_rt->width, storage->frame.current_rt->height); - state.current_tex = RID(); state.current_tex_ptr = NULL; state.current_normal = RID(); @@ -1048,6 +1049,43 @@ void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, cons glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } +void RasterizerCanvasGLES2::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + Vector2 half_size; + if (storage->frame.current_rt) { + half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height); + } else { + half_size = OS::get_singleton()->get_window_size(); + } + half_size *= 0.5; + Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y); + Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y); + + float aspect_ratio = p_rect.size.x / p_rect.size.y; + + // setup our lens shader + state.lens_shader.bind(); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::OFFSET, offset); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::SCALE, scale); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::K1, p_k1); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::K2, p_k2); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::EYE_CENTER, p_eye_center); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::UPSCALE, p_oversample); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::ASPECT_RATIO, aspect_ratio); + + // bind our quad buffer + _bind_quad_buffer(); + + // and draw + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // and cleanup + glBindBuffer(GL_ARRAY_BUFFER, 0); + + for (int i = 0; i < VS::ARRAY_MAX; i++) { + glDisableVertexAttribArray(i); + } +} + void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) { } @@ -1073,6 +1111,7 @@ void RasterizerCanvasGLES2::initialize() { // polygon buffer { uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); poly_size *= 1024; poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); glGenBuffers(1, &data.polygon_buffer); @@ -1084,6 +1123,7 @@ void RasterizerCanvasGLES2::initialize() { glBindBuffer(GL_ARRAY_BUFFER, 0); uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); index_size *= 1024; // kb glGenBuffers(1, &data.polygon_index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); @@ -1147,7 +1187,6 @@ void RasterizerCanvasGLES2::initialize() { _EIDX(1, 1), _EIDX(1, 2), _EIDX(2, 2), _EIDX(2, 2), _EIDX(2, 1), _EIDX(1, 1) }; - ; #undef _EIDX glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW); @@ -1160,6 +1199,10 @@ void RasterizerCanvasGLES2::initialize() { state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); state.canvas_shader.bind(); + + state.lens_shader.init(); + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false)); } void RasterizerCanvasGLES2::finalize() { diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index cda3ec79e7..cf1c239b6e 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -34,6 +34,7 @@ #include "servers/visual/rasterizer.h" #include "shaders/canvas.glsl.gen.h" +#include "shaders/lens_distorted.glsl.gen.h" // #include "shaders/canvas_shadow.glsl.gen.h" @@ -70,6 +71,7 @@ public: bool canvas_texscreen_used; CanvasShaderGLES2 canvas_shader; // CanvasShadowShaderGLES3 canvas_shadow_shader; + LensDistortedShaderGLES2 lens_shader; bool using_texture_rect; bool using_ninepatch; @@ -117,6 +119,7 @@ public: void _bind_quad_buffer(); void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); + void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); void initialize(); void finalize(); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index efeab48ea2..175587b1bb 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -27,12 +27,12 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "rasterizer_gles2.h" -#include "gl_context/context_gl.h" -#include "os/os.h" -#include "project_settings.h" -#include <string.h> +#include "core/os/os.h" +#include "core/project_settings.h" +#include "drivers/gl_context/context_gl.h" #define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 #define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 @@ -64,6 +64,21 @@ #define GLAPIENTRY #endif +#if !defined(GLES_OVER_GL) && !defined(IPHONE_ENABLED) +// Used for debugging on mobile, but not iOS as EGL is not available +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <GLES2/gl2platform.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#endif + +#if defined(MINGW_ENABLED) || defined(_MSC_VER) +#define strcpy strcpy_s +#endif + +#ifndef IPHONE_ENABLED static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) { if (type == _EXT_DEBUG_TYPE_OTHER_ARB) @@ -73,6 +88,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL return; //these are ultimately annoying, so removing for now char debSource[256], debType[256], debSev[256]; + if (source == _EXT_DEBUG_SOURCE_API_ARB) strcpy(debSource, "OpenGL"); else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB) @@ -110,6 +126,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL ERR_PRINTS(output); } +#endif // IPHONE_ENABLED typedef void (*DEBUGPROCARB)(GLenum source, GLenum type, @@ -179,7 +196,7 @@ Error RasterizerGLES2::is_viable() { return ERR_UNAVAILABLE; } } -#endif +#endif // GLES_OVER_GL #endif // GLAD_ENABLED @@ -191,7 +208,7 @@ void RasterizerGLES2::initialize() { print_verbose("Using GLES2 video driver"); #ifdef GLAD_ENABLED - if (true || OS::get_singleton()->is_stdout_verbose()) { + if (OS::get_singleton()->is_stdout_verbose()) { if (GLAD_GL_ARB_debug_output) { glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); glDebugMessageCallbackARB(_gl_debug_print, NULL); @@ -204,7 +221,7 @@ void RasterizerGLES2::initialize() { // For debugging #ifdef GLES_OVER_GL - if (GLAD_GL_ARB_debug_output) { + if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) { glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); @@ -217,7 +234,24 @@ void RasterizerGLES2::initialize() { GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello"); */ } -#endif +#else +#ifndef IPHONE_ENABLED + if (OS::get_singleton()->is_stdout_verbose()) { + DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback"); + if (!callback) { + callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR"); + } + + if (callback) { + + print_line("godot: ENABLING GL DEBUG"); + glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + callback(_gl_debug_print, NULL); + glEnable(_EXT_DEBUG_OUTPUT); + } + } +#endif // !IPHONE_ENABLED +#endif // GLES_OVER_GL const GLubyte *renderer = glGetString(GL_RENDERER); print_line("OpenGL ES 2.0 Renderer: " + String((const char *)renderer)); @@ -380,6 +414,26 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re canvas->canvas_end(); } +void RasterizerGLES2::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + ERR_FAIL_COND(storage->frame.current_rt); + + RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + glDisable(GL_BLEND); + + // render to our framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); + + // output our texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rt->color); + + canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample); + + glBindTexture(GL_TEXTURE_2D, 0); +} + void RasterizerGLES2::end_frame(bool p_swap_buffers) { if (OS::get_singleton()->is_layered_allowed()) { diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index 98c73b776b..97f8ee7c1c 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RASTERIZERGLES2_H #define RASTERIZERGLES2_H @@ -58,6 +59,7 @@ public: virtual void restore_render_target(); virtual void clear_render_target(const Color &p_color); virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0); + virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); virtual void end_frame(bool p_swap_buffers); virtual void finalize(); @@ -65,6 +67,8 @@ public: static void make_current(); static void register_config(); + virtual bool is_low_end() const { return true; } + RasterizerGLES2(); ~RasterizerGLES2(); }; diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index e21998d55e..c4b6c607a2 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -27,20 +27,23 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "rasterizer_scene_gles2.h" -#include "math/transform.h" -#include "math_funcs.h" -#include "os/os.h" -#include "project_settings.h" + +#include "core/math/math_funcs.h" +#include "core/math/transform.h" +#include "core/os/os.h" +#include "core/project_settings.h" +#include "core/vmap.h" #include "rasterizer_canvas_gles2.h" #include "servers/visual/visual_server_raster.h" -#include "vmap.h" - #ifndef GLES_OVER_GL #define glClearDepth glClearDepthf #endif +#define _DEPTH_COMPONENT24_OES 0x81A6 + static const GLenum _cube_side_enum[6] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, @@ -109,8 +112,8 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) { glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadow_atlas->size, shadow_atlas->size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -436,29 +439,206 @@ void RasterizerSceneGLES2::reflection_atlas_set_subdivision(RID p_ref_atlas, int //////////////////////////////////////////////////// RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) { - return RID(); + + RasterizerStorageGLES2::ReflectionProbe *probe = storage->reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!probe, RID()); + + ReflectionProbeInstance *rpi = memnew(ReflectionProbeInstance); + + rpi->probe_ptr = probe; + rpi->self = reflection_probe_instance_owner.make_rid(rpi); + rpi->probe = p_probe; + rpi->reflection_atlas_index = -1; + rpi->render_step = -1; + rpi->last_pass = 0; + rpi->current_resolution = 0; + rpi->dirty = true; + + rpi->last_pass = 0; + rpi->index = 0; + + for (int i = 0; i < 6; i++) { + glGenFramebuffers(1, &rpi->fbo[i]); + } + + glGenFramebuffers(1, &rpi->fbo_blur); + glGenRenderbuffers(1, &rpi->depth); + rpi->cubemap = 0; + //glGenTextures(1, &rpi->cubemap); + + return rpi->self; } void RasterizerSceneGLES2::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + rpi->transform = p_transform; } void RasterizerSceneGLES2::reflection_probe_release_atlas_index(RID p_instance) { } bool RasterizerSceneGLES2::reflection_probe_instance_needs_redraw(RID p_instance) { - return false; + const ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + bool need_redraw = rpi->probe_ptr->resolution != rpi->current_resolution || rpi->dirty || rpi->probe_ptr->update_mode == VS::REFLECTION_PROBE_UPDATE_ALWAYS; + rpi->dirty = false; + return need_redraw; } bool RasterizerSceneGLES2::reflection_probe_instance_has_reflection(RID p_instance) { - return false; + return true; } bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { - return false; + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + rpi->render_step = 0; + + if (rpi->probe_ptr->resolution != rpi->current_resolution) { + + //update cubemap if resolution changed + int size = rpi->probe_ptr->resolution; + rpi->current_resolution = size; + + GLenum internal_format = GL_RGB; + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; + + glActiveTexture(GL_TEXTURE0); + if (rpi->cubemap != 0) { + glDeleteTextures(1, &rpi->cubemap); + } + glGenTextures(1, &rpi->cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); +#if 1 + //Mobile hardware (PowerVR specially) prefers this approach, the other one kills the game + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL); + } + + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + + glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); //resize depth buffer + glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size); + + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); + } + +#else + int lod = 0; + + //the approach below is fatal for powervr + + // Set the initial (empty) mipmaps, all need to be set for this to work in GLES2, even if later wont be used. + while (size >= 1) { + + for (int i = 0; i < 6; i++) { + glTexImage2D(_cube_side_enum[i], lod, internal_format, size, size, 0, format, type, NULL); + if (size == rpi->current_resolution) { + //adjust framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0); + glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); + glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); + +#ifdef DEBUG_ENABLED + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); +#endif + } + } + + lod++; + + size >>= 1; + } +#endif + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + return true; } bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_instance) { - return false; + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + int size = rpi->probe_ptr->resolution; + + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + + for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { + glDisableVertexAttribArray(i); + } + } + + //vdc cache + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex); + + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo_blur); + // now render to the framebuffer, mipmap level for mipmap level + int lod = 1; + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to + + size >>= 1; + int mipmaps = 6; + int mm_level = mipmaps - 1; + + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); + storage->shaders.cubemap_filter.bind(); + + //blur + while (size >= 1) { + + for (int i = 0; i < 6; i++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, lod); + + glViewport(0, 0, size, size); + storage->bind_quad_array(); + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); + float roughness = CLAMP(lod / (float)(mipmaps - 1), 0, 1); + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness); + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + size >>= 1; + + mm_level--; + + lod++; + } + + // restore ranges + + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return true; } /* ENVIRONMENT API */ @@ -562,20 +742,38 @@ void RasterizerSceneGLES2::environment_set_adjustment(RID p_env, bool p_enable, } void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + + env->fog_enabled = p_enable; + env->fog_color = p_color; + env->fog_sun_color = p_sun_color; + env->fog_sun_amount = p_sun_amount; } void RasterizerSceneGLES2::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + + env->fog_depth_enabled = p_enable; + env->fog_depth_begin = p_depth_begin; + env->fog_depth_curve = p_depth_curve; + env->fog_transmit_enabled = p_transmit; + env->fog_transmit_curve = p_transmit_curve; } void RasterizerSceneGLES2::environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); -} + env->fog_height_enabled = p_enable; + env->fog_height_min = p_min_height; + env->fog_height_max = p_max_height; + env->fog_height_curve = p_height_curve; +} bool RasterizerSceneGLES2::is_environment(RID p_env) { return environment_owner.owns(p_env); } @@ -603,6 +801,8 @@ RID RasterizerSceneGLES2::light_instance_create(RID p_light) { light_instance->light = p_light; light_instance->light_ptr = storage->light_owner.getornull(p_light); + light_instance->light_index = 0xFFFF; + ERR_FAIL_COND_V(!light_instance->light_ptr, RID()); light_instance->self = light_instance_owner.make_rid(light_instance); @@ -708,9 +908,39 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G bool has_blend_alpha = p_material->shader->spatial.blend_mode != RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX; bool has_alpha = has_base_alpha || has_blend_alpha; - // TODO add this stuff - // bool mirror = p_instance->mirror; - // bool no_cull = false; + bool mirror = p_instance->mirror; + + if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED) { + mirror = false; + } else if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_FRONT) { + mirror = !mirror; + } + + //if (p_material->shader->spatial.uses_sss) { + // state.used_sss = true; + //} + + if (p_material->shader->spatial.uses_screen_texture) { + state.used_screen_texture = true; + } + + if (p_depth_pass) { + + if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) + return; //bye + + if (!p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + //shader does not use discard and does not write a vertex position, use generic material + if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { + p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); + mirror = false; + } else { + p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); + } + } + + has_alpha = false; + } RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); @@ -723,46 +953,130 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G e->instance = p_instance; e->owner = p_owner; e->sort_key = 0; + e->depth_key = 0; + e->use_accum = false; + e->light_index = RenderList::MAX_LIGHTS; + e->use_accum_ptr = &e->use_accum; + e->instancing = (e->instance->base_type == VS::INSTANCE_MULTIMESH) ? 1 : 0; + + if (e->geometry->last_pass != render_pass) { + e->geometry->last_pass = render_pass; + e->geometry->index = current_geometry_index++; + } - // TODO check render pass of geometry - - // TODO check directional light flag + e->geometry_index = e->geometry->index; - if (p_depth_pass) { - // if we are in the depth pass we can sort out a few things to improve performance + if (e->material->last_pass != render_pass) { + e->material->last_pass = render_pass; + e->material->index = current_material_index++; - if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) { - return; + if (e->material->shader->last_pass != render_pass) { + e->material->shader->index = current_shader_index++; } + } + + e->material_index = e->material->index; - if (p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + e->refprobe_0_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default + e->refprobe_1_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default - // shader doesn't use discard or writes a custom vertex position, - // so we can use a stripped down shader instead + if (!p_depth_pass) { - // TODO twosided and worldcoord stuff + e->depth_layer = e->instance->depth_layer; + e->priority = p_material->render_priority; - p_material = storage->material_owner.getptr(default_material_twosided); + int rpsize = e->instance->reflection_probe_instances.size(); + if (rpsize > 0) { + bool first = true; + rpsize = MIN(rpsize, 2); //more than 2 per object are not supported, this keeps it stable + + for (int i = 0; i < rpsize; i++) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(e->instance->reflection_probe_instances[i]); + if (rpi->last_pass != render_pass) { + continue; + } + if (first) { + e->refprobe_0_index = rpi->index; + first = false; + } else { + e->refprobe_1_index = rpi->index; + break; + } + } + + /* if (e->refprobe_0_index > e->refprobe_1_index) { //if both are valid, swap them to keep order as best as possible + uint64_t tmp = e->refprobe_0_index; + e->refprobe_0_index = e->refprobe_1_index; + e->refprobe_1_index = tmp; + }*/ } - has_alpha = false; - } + //add directional lights - e->sort_key |= uint64_t(e->geometry->index) << RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT; - e->sort_key |= uint64_t(e->instance->base_type) << RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT; + if (p_material->shader->spatial.unshaded) { + e->light_mode = LIGHTMODE_UNSHADED; + } else { - if (p_material->shader->spatial.unshaded) { - e->sort_key |= SORT_KEY_UNSHADED_FLAG; - } + bool copy = false; - if (!p_depth_pass) { - e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; + for (int i = 0; i < render_directional_lights; i++) { - e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; - } else { - // TODO + if (copy) { + RenderList::Element *e2 = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + if (!e2) { + break; + } + *e2 = *e; //this includes accum ptr :) + e = e2; + } + + //directional sort key + e->light_type1 = 0; + e->light_type2 = 1; + e->light_index = i; + + copy = true; + } + + //add omni / spots + + for (int i = 0; i < e->instance->light_instances.size(); i++) { + + LightInstance *li = light_instance_owner.getornull(e->instance->light_instances[i]); + + if (li->light_index >= render_light_instance_count) { + continue; // too many + } + + if (copy) { + RenderList::Element *e2 = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + if (!e2) { + break; + } + *e2 = *e; //this includes accum ptr :) + e = e2; + } + + //directional sort key + e->light_type1 = 1; + e->light_type2 = li->light_ptr->type == VisualServer::LIGHT_OMNI ? 0 : 1; + e->light_index = li->light_index; + + copy = true; + } + + if (e->instance->lightmap.is_valid()) { + e->light_mode = LIGHTMODE_LIGHTMAP; + } else if (!e->instance->lightmap_capture_data.empty()) { + e->light_mode = LIGHTMODE_LIGHTMAP_CAPTURE; + } else { + e->light_mode = LIGHTMODE_NORMAL; + } + } } + // do not add anything here, as lights are duplicated elements.. + if (p_material->shader->spatial.uses_time) { VisualServerRaster::redraw_request(); } @@ -770,6 +1084,13 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass) { + render_pass++; + current_material_index = 0; + current_geometry_index = 0; + current_light_index = 0; + current_refprobe_index = 0; + current_shader_index = 0; + for (int i = 0; i < p_cull_count; i++) { InstanceBase *instance = p_cull_result[i]; @@ -820,9 +1141,7 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p } break; - default: { - - } break; + default: {} } } } @@ -837,13 +1156,13 @@ static const GLenum gl_primitive[] = { GL_TRIANGLE_FAN }; -void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size) { +bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size) { // material parameters state.scene_shader.set_custom_shader(p_material->shader->custom_code_id); - state.scene_shader.bind(); + bool shader_rebind = state.scene_shader.bind(); if (p_material->shader->spatial.no_depth_test) { glDisable(GL_DEPTH_TEST); @@ -922,203 +1241,178 @@ void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m glBindTexture(t->target, t->tex_id); } state.scene_shader.use_material((void *)p_material); + + return shader_rebind; } void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, p_skeleton != NULL); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, !storage->config.float_texture_supported); - // state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, true); - switch (p_element->instance->base_type) { case VS::INSTANCE_MESH: { RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, s->attribs[VS::ARRAY_COLOR].enabled); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, s->attribs[VS::ARRAY_TEX_UV].enabled); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, s->attribs[VS::ARRAY_TEX_UV2].enabled); - - } break; - - case VS::INSTANCE_MULTIMESH: { - RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner); - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, true); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, true); - - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, s->attribs[VS::ARRAY_TEX_UV].enabled); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, s->attribs[VS::ARRAY_TEX_UV2].enabled); - } break; - - case VS::INSTANCE_IMMEDIATE: { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, true); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, true); - state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, true); - } break; - - default: { - - } break; - } - - if (storage->config.float_texture_supported) { - if (p_skeleton) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, p_skeleton->tex_id); - } - - return; - } - - if (p_skeleton) { - ERR_FAIL_COND(p_skeleton->use_2d); - - PoolVector<float> &transform_buffer = storage->resources.skeleton_transform_cpu_buffer; - - switch (p_element->instance->base_type) { - case VS::INSTANCE_MESH: { - RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); + glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - if (!s->attribs[VS::ARRAY_BONES].enabled || !s->attribs[VS::ARRAY_WEIGHTS].enabled) { - break; // the whole instance has a skeleton, but this surface is not affected by it. - } + if (s->index_array_len > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); + } - // 3 * vec4 per vertex - if (transform_buffer.size() < s->array_len * 12) { - transform_buffer.resize(s->array_len * 12); + for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { + if (s->attribs[i].enabled) { + glEnableVertexAttribArray(i); + glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, (uint8_t *)0 + s->attribs[i].offset); + } else { + glDisableVertexAttribArray(i); + switch (i) { + case VS::ARRAY_NORMAL: { + glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); + } break; + case VS::ARRAY_COLOR: { + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + + } break; + default: {} + } } + } - const size_t bones_offset = s->attribs[VS::ARRAY_BONES].offset; - const size_t bones_stride = s->attribs[VS::ARRAY_BONES].stride; - const size_t bone_weight_offset = s->attribs[VS::ARRAY_WEIGHTS].offset; - const size_t bone_weight_stride = s->attribs[VS::ARRAY_WEIGHTS].stride; + bool clear_skeleton_buffer = !storage->config.float_texture_supported; - { - PoolVector<float>::Write write = transform_buffer.write(); - float *buffer = write.ptr(); + if (p_skeleton) { - PoolVector<uint8_t>::Read vertex_array_read = s->data.read(); - const uint8_t *vertex_data = vertex_array_read.ptr(); + if (storage->config.float_texture_supported) { + //use float texture workflow + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); + glBindTexture(GL_TEXTURE_2D, p_skeleton->tex_id); + } else { + //use transform buffer workflow + ERR_FAIL_COND(p_skeleton->use_2d); - for (int i = 0; i < s->array_len; i++) { + PoolVector<float> &transform_buffer = storage->resources.skeleton_transform_cpu_buffer; - // do magic + if (!s->attribs[VS::ARRAY_BONES].enabled || !s->attribs[VS::ARRAY_WEIGHTS].enabled) { + break; // the whole instance has a skeleton, but this surface is not affected by it. + } - size_t bones[4]; - float bone_weight[4]; + // 3 * vec4 per vertex + if (transform_buffer.size() < s->array_len * 12) { + transform_buffer.resize(s->array_len * 12); + } - if (s->attribs[VS::ARRAY_BONES].type == GL_UNSIGNED_BYTE) { - // read as byte - const uint8_t *bones_ptr = vertex_data + bones_offset + (i * bones_stride); - bones[0] = bones_ptr[0]; - bones[1] = bones_ptr[1]; - bones[2] = bones_ptr[2]; - bones[3] = bones_ptr[3]; - } else { - // read as short - const uint16_t *bones_ptr = (const uint16_t *)(vertex_data + bones_offset + (i * bones_stride)); - bones[0] = bones_ptr[0]; - bones[1] = bones_ptr[1]; - bones[2] = bones_ptr[2]; - bones[3] = bones_ptr[3]; + const size_t bones_offset = s->attribs[VS::ARRAY_BONES].offset; + const size_t bones_stride = s->attribs[VS::ARRAY_BONES].stride; + const size_t bone_weight_offset = s->attribs[VS::ARRAY_WEIGHTS].offset; + const size_t bone_weight_stride = s->attribs[VS::ARRAY_WEIGHTS].stride; + + { + PoolVector<float>::Write write = transform_buffer.write(); + float *buffer = write.ptr(); + + PoolVector<uint8_t>::Read vertex_array_read = s->data.read(); + const uint8_t *vertex_data = vertex_array_read.ptr(); + + for (int i = 0; i < s->array_len; i++) { + + // do magic + + size_t bones[4]; + float bone_weight[4]; + + if (s->attribs[VS::ARRAY_BONES].type == GL_UNSIGNED_BYTE) { + // read as byte + const uint8_t *bones_ptr = vertex_data + bones_offset + (i * bones_stride); + bones[0] = bones_ptr[0]; + bones[1] = bones_ptr[1]; + bones[2] = bones_ptr[2]; + bones[3] = bones_ptr[3]; + } else { + // read as short + const uint16_t *bones_ptr = (const uint16_t *)(vertex_data + bones_offset + (i * bones_stride)); + bones[0] = bones_ptr[0]; + bones[1] = bones_ptr[1]; + bones[2] = bones_ptr[2]; + bones[3] = bones_ptr[3]; + } + + if (s->attribs[VS::ARRAY_WEIGHTS].type == GL_FLOAT) { + // read as float + const float *weight_ptr = (const float *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); + bone_weight[0] = weight_ptr[0]; + bone_weight[1] = weight_ptr[1]; + bone_weight[2] = weight_ptr[2]; + bone_weight[3] = weight_ptr[3]; + } else { + // read as half + const uint16_t *weight_ptr = (const uint16_t *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); + bone_weight[0] = (weight_ptr[0] / (float)0xFFFF); + bone_weight[1] = (weight_ptr[1] / (float)0xFFFF); + bone_weight[2] = (weight_ptr[2] / (float)0xFFFF); + bone_weight[3] = (weight_ptr[3] / (float)0xFFFF); + } + + Transform transform; + + Transform bone_transforms[4] = { + storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[0]), + storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[1]), + storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[2]), + storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[3]), + }; + + transform.origin = + bone_weight[0] * bone_transforms[0].origin + + bone_weight[1] * bone_transforms[1].origin + + bone_weight[2] * bone_transforms[2].origin + + bone_weight[3] * bone_transforms[3].origin; + + transform.basis = + bone_transforms[0].basis * bone_weight[0] + + bone_transforms[1].basis * bone_weight[1] + + bone_transforms[2].basis * bone_weight[2] + + bone_transforms[3].basis * bone_weight[3]; + + float row[3][4] = { + { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] }, + { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] }, + { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, + }; + + size_t transform_buffer_offset = i * 12; + + copymem(&buffer[transform_buffer_offset], row, sizeof(row)); } + } - if (s->attribs[VS::ARRAY_WEIGHTS].type == GL_FLOAT) { - // read as float - const float *weight_ptr = (const float *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); - bone_weight[0] = weight_ptr[0]; - bone_weight[1] = weight_ptr[1]; - bone_weight[2] = weight_ptr[2]; - bone_weight[3] = weight_ptr[3]; - } else { - // read as half - const uint16_t *weight_ptr = (const uint16_t *)(vertex_data + bone_weight_offset + (i * bone_weight_stride)); - bone_weight[0] = (weight_ptr[0] / (float)0xFFFF); - bone_weight[1] = (weight_ptr[1] / (float)0xFFFF); - bone_weight[2] = (weight_ptr[2] / (float)0xFFFF); - bone_weight[3] = (weight_ptr[3] / (float)0xFFFF); - } - - size_t offset = i * 12; - - Transform transform; - - Transform bone_transforms[4] = { - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[0]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[1]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[2]), - storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[3]), - }; - - transform.origin = - bone_weight[0] * bone_transforms[0].origin + - bone_weight[1] * bone_transforms[1].origin + - bone_weight[2] * bone_transforms[2].origin + - bone_weight[3] * bone_transforms[3].origin; + storage->_update_skeleton_transform_buffer(transform_buffer, s->array_len * 12); - transform.basis = - bone_transforms[0].basis * bone_weight[0] + - bone_transforms[1].basis * bone_weight[1] + - bone_transforms[2].basis * bone_weight[2] + - bone_transforms[3].basis * bone_weight[3]; + //enable transform buffer and bind it + glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - float row[3][4] = { - { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] }, - { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] }, - { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, - }; + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 2); - size_t transform_buffer_offset = i * 12; + glVertexAttribPointer(INSTANCE_BONE_BASE + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); + glVertexAttribPointer(INSTANCE_BONE_BASE + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); + glVertexAttribPointer(INSTANCE_BONE_BASE + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); - copymem(&buffer[transform_buffer_offset], row, sizeof(row)); - } + clear_skeleton_buffer = false; } + } - storage->_update_skeleton_transform_buffer(transform_buffer, s->array_len * 12); - } break; - - default: { - - } break; - } - } -} - -void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { + if (clear_skeleton_buffer) { - switch (p_element->instance->base_type) { + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 2); + } - case VS::INSTANCE_MESH: { + } break; + case VS::INSTANCE_MULTIMESH: { RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - // set up - - if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { - glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - - glEnableVertexAttribArray(VS::ARRAY_MAX + 0); - glEnableVertexAttribArray(VS::ARRAY_MAX + 1); - glEnableVertexAttribArray(VS::ARRAY_MAX + 2); - - glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); - glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); - glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); - } else { - // just to make sure - glDisableVertexAttribArray(VS::ARRAY_MAX + 0); - glDisableVertexAttribArray(VS::ARRAY_MAX + 1); - glDisableVertexAttribArray(VS::ARRAY_MAX + 2); - - glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); - } - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); if (s->index_array_len > 0) { @@ -1131,61 +1425,58 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, (uint8_t *)0 + s->attribs[i].offset); } else { glDisableVertexAttribArray(i); + switch (i) { + case VS::ARRAY_NORMAL: { + glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); + } break; + case VS::ARRAY_COLOR: { + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + + } break; + default: {} + } } } - // drawing - - if (s->index_array_len > 0) { - glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); - } else { - glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); - } - - // tear down + // prepare multimesh (disable) + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 0); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 1); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 2); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 3); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 4); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 2); - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - glDisableVertexAttribArray(i); - } - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } + } break; - if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { - glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); + case VS::INSTANCE_IMMEDIATE: { + } break; - glDisableVertexAttribArray(VS::ARRAY_MAX + 0); - glDisableVertexAttribArray(VS::ARRAY_MAX + 1); - glDisableVertexAttribArray(VS::ARRAY_MAX + 2); - } + default: {} + } +} - glBindBuffer(GL_ARRAY_BUFFER, 0); +void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { - } break; + switch (p_element->instance->base_type) { - case VS::INSTANCE_MULTIMESH: { + case VS::INSTANCE_MESH: { - RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner); RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - if (amount == -1) { - amount = multi_mesh->size; - } + // drawing + if (s->index_array_len > 0) { + glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); + } else { + glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); + } + /* if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { + //clean up after skeleton glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - glEnableVertexAttribArray(VS::ARRAY_MAX + 0); - glEnableVertexAttribArray(VS::ARRAY_MAX + 1); - glEnableVertexAttribArray(VS::ARRAY_MAX + 2); - - glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); - glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); - glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); - } else { - // just to make sure glDisableVertexAttribArray(VS::ARRAY_MAX + 0); glDisableVertexAttribArray(VS::ARRAY_MAX + 1); glDisableVertexAttribArray(VS::ARRAY_MAX + 2); @@ -1194,37 +1485,20 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); } +*/ + } break; - glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); - } - - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - if (s->attribs[i].enabled) { - glEnableVertexAttribArray(i); - glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, (uint8_t *)0 + s->attribs[i].offset); - } else { - glDisableVertexAttribArray(i); - } - } + case VS::INSTANCE_MULTIMESH: { - glDisableVertexAttribArray(12); // transform 0 - glDisableVertexAttribArray(13); // transform 1 - glDisableVertexAttribArray(14); // transform 2 - glDisableVertexAttribArray(15); // color - glDisableVertexAttribArray(8); // custom data + RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner); + RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); - if (!s->attribs[VS::ARRAY_COLOR].enabled) { - glDisableVertexAttribArray(VS::ARRAY_COLOR); + int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); - glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); + if (amount == -1) { + amount = multi_mesh->size; } - glVertexAttrib4f(15, 1, 1, 1, 1); - glVertexAttrib4f(8, 0, 0, 0, 0); - int stride = multi_mesh->color_floats + multi_mesh->custom_data_floats + multi_mesh->xform_floats; int color_ofs = multi_mesh->xform_floats; @@ -1232,49 +1506,34 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { // drawing + const float *base_buffer = multi_mesh->data.ptr(); + for (int i = 0; i < amount; i++) { - float *buffer = &multi_mesh->data.write[i * stride]; + const float *buffer = base_buffer + i * stride; { - // inline of multimesh_get_transform since it's such a pain - // to get a RID from here... - Transform transform; - - transform.basis.elements[0][0] = buffer[0]; - transform.basis.elements[0][1] = buffer[1]; - transform.basis.elements[0][2] = buffer[2]; - transform.origin.x = buffer[3]; - transform.basis.elements[1][0] = buffer[4]; - transform.basis.elements[1][1] = buffer[5]; - transform.basis.elements[1][2] = buffer[6]; - transform.origin.y = buffer[7]; - transform.basis.elements[2][0] = buffer[8]; - transform.basis.elements[2][1] = buffer[9]; - transform.basis.elements[2][2] = buffer[10]; - transform.origin.z = buffer[11]; - - float row[3][4] = { - { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] }, - { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] }, - { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, - }; - - glVertexAttrib4fv(12, row[0]); - glVertexAttrib4fv(13, row[1]); - glVertexAttrib4fv(14, row[2]); + + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]); } if (multi_mesh->color_floats) { if (multi_mesh->color_format == VS::MULTIMESH_COLOR_8BIT) { uint8_t *color_data = (uint8_t *)(buffer + color_ofs); - glVertexAttrib4f(15, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); } else { - glVertexAttrib4fv(15, buffer + color_ofs); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); } } if (multi_mesh->custom_data_floats) { - glVertexAttrib4fv(8, buffer + custom_data_ofs); + if (multi_mesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { + uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); + } else { + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 4, buffer + custom_data_ofs); + } } if (s->index_array_len > 0) { @@ -1284,25 +1543,6 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { } } - // tear down - - for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { - glDisableVertexAttribArray(i); - } - - if (s->index_array_len > 0) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { - glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - - glDisableVertexAttribArray(VS::ARRAY_MAX + 0); - glDisableVertexAttribArray(VS::ARRAY_MAX + 1); - glDisableVertexAttribArray(VS::ARRAY_MAX + 2); - } - - glBindBuffer(GL_ARRAY_BUFFER, 0); } break; case VS::INSTANCE_IMMEDIATE: { @@ -1416,508 +1656,731 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { } } break; + default: {} } } -void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_directional_lights, int p_directional_light_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add) { - - ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); +void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas) { - Vector2 screen_pixel_size; - screen_pixel_size.x = 1.0 / storage->frame.current_rt->width; - screen_pixel_size.y = 1.0 / storage->frame.current_rt->height; + //turn off all by default + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, false); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, false); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_DIRECTIONAL, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, false); - bool use_radiance_map = false; + if (!p_light) { //no light, return off + return; + } - VMap<RID, Vector<RenderList::Element *> > lit_objects; + //turn on lighting + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, true); - for (int i = 0; i < p_element_count; i++) { - RenderList::Element *e = p_elements[i]; + switch (p_light->light_ptr->type) { + case VS::LIGHT_DIRECTIONAL: { - RasterizerStorageGLES2::Material *material = e->material; + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_DIRECTIONAL, true); + switch (p_light->light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { + //no need + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true); - RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); + } break; + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true); + } break; + } - if (p_base_env) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); - glBindTexture(GL_TEXTURE_CUBE_MAP, p_base_env); - use_radiance_map = true; - } - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map); + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, p_light->light_ptr->directional_blend_splits); + if (!state.render_no_shadows && p_light->light_ptr->shadow) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); + } - if (material->shader->spatial.unshaded) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); - } else { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map); - } + } break; + case VS::LIGHT_OMNI: { + + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true); + if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); + } + } break; + case VS::LIGHT_SPOT: { + + state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true); + if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_5, shadow_filter_mode == SHADOW_FILTER_PCF5); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADOW_MODE_PCF_13, shadow_filter_mode == SHADOW_FILTER_PCF13); + } + } break; + } +} - // opaque pass +void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform) { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false); + RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; - _setup_geometry(e, skeleton); + //common parameters + float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + float sign = light_ptr->negative ? -1 : 1; - _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular); + Color color = light_ptr->color * sign * energy * Math_PI; + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, color); - if (use_radiance_map) { - state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform); - } + //specific parameters - if (p_shadow) { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_NORMAL_BIAS, p_shadow_normal_bias); - } + switch (light_ptr->type) { + case VS::LIGHT_DIRECTIONAL: { + //not using inverse for performance, view should be normalized anyway + Vector3 direction = p_view_transform.basis.xform_inv(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - if (p_env) { - state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, p_env->ambient_energy); + CameraMatrix matrices[4]; - } else { - state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, Color(1.0, 1.0, 1.0, 1.0)); - state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0); - } + if (!state.render_no_shadows && light_ptr->shadow && directional_shadow.depth) { - glEnable(GL_BLEND); + int shadow_count = 0; + Color split_offsets; - if (p_alpha_pass || p_directional_add) { - int desired_blend_mode; - if (p_directional_add) { - desired_blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD; - } else { - desired_blend_mode = material->shader->spatial.blend_mode; - } + switch (light_ptr->directional_shadow_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { + shadow_count = 1; + } break; - switch (desired_blend_mode) { + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { + shadow_count = 2; + } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } + case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { + shadow_count = 4; + } break; + } - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD: { + for (int k = 0; k < shadow_count; k++) { - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(p_alpha_pass ? GL_SRC_ALPHA : GL_ONE, GL_ONE); + uint32_t x = light->directional_rect.position.x; + uint32_t y = light->directional_rect.position.y; + uint32_t width = light->directional_rect.size.x; + uint32_t height = light->directional_rect.size.y; - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB: { + if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { - glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); - } break; - case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MUL: { - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); - } else { - glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); - } + width /= 2; + height /= 2; - } break; - } - } else { - // no blend mode given - assume mix - glBlendEquation(GL_FUNC_ADD); - if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { - glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - } else { - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - } + if (k == 0) { - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + } else if (k == 1) { + x += width; + } else if (k == 2) { + y += height; + } else if (k == 3) { + x += width; + y += height; + } - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + } else if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + height /= 2; - _render_geometry(e); + if (k == 0) { - if (material->shader->spatial.unshaded) - continue; + } else { + y += height; + } + } - if (p_shadow) - continue; + split_offsets[k] = light->shadow_transform[k].split; - for (int light = 0; light < e->instance->light_instances.size(); light++) { + Transform modelview = (p_view_transform.inverse() * light->shadow_transform[k].transform).affine_inverse(); - RID light_instance = e->instance->light_instances[light]; + CameraMatrix bias; + bias.set_light_bias(); + CameraMatrix rectm; + Rect2 atlas_rect = Rect2(float(x) / directional_shadow.size, float(y) / directional_shadow.size, float(width) / directional_shadow.size, float(height) / directional_shadow.size); + rectm.set_light_atlas_rect(atlas_rect); - lit_objects[light_instance].push_back(e); - } - } + CameraMatrix shadow_mtx = rectm * bias * light->shadow_transform[k].camera * modelview; + matrices[k] = shadow_mtx; - if (p_shadow) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); - return; - } + /*Color light_clamp; + light_clamp[0] = atlas_rect.position.x; + light_clamp[1] = atlas_rect.position.y; + light_clamp[2] = atlas_rect.size.x; + light_clamp[3] = atlas_rect.size.y;*/ + } - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, true); + // state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / directional_shadow.size, 1.0 / directional_shadow.size)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPLIT_OFFSETS, split_offsets); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, matrices[0]); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX2, matrices[1]); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX3, matrices[2]); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX4, matrices[3]); + } + } break; + case VS::LIGHT_OMNI: { - glEnable(GL_BLEND); - glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + Vector3 position = p_view_transform.xform_inv(light->transform.origin); - for (int lo = 0; lo < lit_objects.size(); lo++) { + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); - RID key = lit_objects.getk(lo); + float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - LightInstance *light = light_instance_owner.getornull(key); - RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; + float attenuation = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - const Vector<RenderList::Element *> &list = lit_objects.getv(lo); + if (!state.render_no_shadows && light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { - for (int i = 0; i < list.size(); i++) { + uint32_t key = shadow_atlas->shadow_owners[light->self]; - RenderList::Element *e = list[i]; - RasterizerStorageGLES2::Material *material = e->material; + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); + ERR_BREAK(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); - { - _setup_geometry(e, skeleton); + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size >> 1; - _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); - if (shadow_atlas != NULL) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); - glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); - } + uint32_t x = (quadrant & 1) * quadrant_size; + uint32_t y = (quadrant >> 1) * quadrant_size; - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + uint32_t width = shadow_size; + uint32_t height = shadow_size; - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); - } + if (light->light_ptr->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + height /= 2; + } else { + width /= 2; + } - switch (light_ptr->type) { - case VS::LIGHT_OMNI: { + Transform proj = (p_view_transform.inverse() * light->transform).inverse(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)1); + Color light_clamp; + light_clamp[0] = float(x) / atlas_size; + light_clamp[1] = float(y) / atlas_size; + light_clamp[2] = float(width) / atlas_size; + light_clamp[3] = float(height) / atlas_size; - Vector3 position = p_view_transform.inverse().xform(light->transform.origin); + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / shadow_atlas->size, 1.0 / shadow_atlas->size)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, proj); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + } + } break; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); + case VS::LIGHT_SPOT: { - float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); + Vector3 position = p_view_transform.xform_inv(light->transform.origin); - Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); - if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) { + Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); + float attenuation = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; + float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; + float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE]; + angle = Math::cos(Math::deg2rad(angle)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_RANGE, spot_attenuation); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - uint32_t key = shadow_atlas->shadow_owners[light->self]; + if (!state.render_no_shadows && light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { + uint32_t key = shadow_atlas->shadow_owners[light->self]; - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; + uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; + uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); + ERR_BREAK(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; + uint32_t atlas_size = shadow_atlas->size; + uint32_t quadrant_size = atlas_size >> 1; - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; + uint32_t x = (quadrant & 1) * quadrant_size; + uint32_t y = (quadrant >> 1) * quadrant_size; - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); + x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - uint32_t width = shadow_size; - uint32_t height = shadow_size; + uint32_t width = shadow_size; + uint32_t height = shadow_size; - if (light->light_ptr->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { - height /= 2; - } else { - width /= 2; - } + Rect2 rect(float(x) / atlas_size, float(y) / atlas_size, float(width) / atlas_size, float(height) / atlas_size); - Transform proj = (p_view_transform.inverse() * light->transform).inverse(); + Color light_clamp; + light_clamp[0] = rect.position.x; + light_clamp[1] = rect.position.y; + light_clamp[2] = rect.size.x; + light_clamp[3] = rect.size.y; - Color light_clamp; - light_clamp[0] = float(x) / atlas_size; - light_clamp[1] = float(y) / atlas_size; - light_clamp[2] = float(width) / atlas_size; - light_clamp[3] = float(height) / atlas_size; + Transform modelview = (p_view_transform.inverse() * light->transform).inverse(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, proj); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + CameraMatrix bias; + bias.set_light_bias(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0); - } else { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0); - } - } break; + CameraMatrix rectm; + rectm.set_light_atlas_rect(rect); - case VS::LIGHT_SPOT: { - Vector3 position = p_view_transform.inverse().xform(light->transform.origin); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)2); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position); + CameraMatrix shadow_matrix = rectm * bias * light->shadow_transform[0].camera * modelview; - Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; - float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; - float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; - float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE]; - angle = Math::cos(Math::deg2rad(angle)); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_RANGE, spot_attenuation); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_PIXEL_SIZE, Size2(1.0 / shadow_atlas->size, 1.0 / shadow_atlas->size)); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, shadow_matrix); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + } - if (light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { - uint32_t key = shadow_atlas->shadow_owners[light->self]; + } break; + default: {} + } +} - uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; - uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; +void RasterizerSceneGLES2::_setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env) { - ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); + if (p_refprobe1) { + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_USE_BOX_PROJECT, p_refprobe1->probe_ptr->box_projection); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_EXTENTS, p_refprobe1->probe_ptr->extents); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_OFFSET, p_refprobe1->probe_ptr->origin_offset); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_EXTERIOR, !p_refprobe1->probe_ptr->interior); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_INTENSITY, p_refprobe1->probe_ptr->intensity); - uint32_t atlas_size = shadow_atlas->size; - uint32_t quadrant_size = atlas_size >> 1; + Color ambient; + if (p_refprobe1->probe_ptr->interior) { + ambient = p_refprobe1->probe_ptr->interior_ambient * p_refprobe1->probe_ptr->interior_ambient_energy; + ambient.a = p_refprobe1->probe_ptr->interior_ambient_probe_contrib; + } else if (p_env) { + ambient = p_env->ambient_color * p_env->ambient_energy; + ambient.a = p_env->ambient_sky_contribution; + } - uint32_t x = (quadrant & 1) * quadrant_size; - uint32_t y = (quadrant >> 1) * quadrant_size; + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_AMBIENT, ambient); - uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision); - x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; - y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size; + Transform proj = (p_view_transform.inverse() * p_refprobe1->transform).affine_inverse(); - uint32_t width = shadow_size; - uint32_t height = shadow_size; + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_LOCAL_MATRIX, proj); + } - Rect2 rect(float(x) / atlas_size, float(y) / atlas_size, float(width) / atlas_size, float(height) / atlas_size); + if (p_refprobe2) { + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_USE_BOX_PROJECT, p_refprobe2->probe_ptr->box_projection); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_EXTENTS, p_refprobe2->probe_ptr->extents); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_OFFSET, p_refprobe2->probe_ptr->origin_offset); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, !p_refprobe2->probe_ptr->interior); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_INTENSITY, p_refprobe2->probe_ptr->intensity); + + Color ambient; + if (p_refprobe2->probe_ptr->interior) { + ambient = p_refprobe2->probe_ptr->interior_ambient * p_refprobe2->probe_ptr->interior_ambient_energy; + ambient.a = p_refprobe2->probe_ptr->interior_ambient_probe_contrib; + } else if (p_env) { + ambient = p_env->ambient_color * p_env->ambient_energy; + ambient.a = p_env->ambient_sky_contribution; + } - Color light_clamp; - light_clamp[0] = rect.position.x; - light_clamp[1] = rect.position.y; - light_clamp[2] = rect.size.x; - light_clamp[3] = rect.size.y; + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_AMBIENT, ambient); - Transform modelview = (p_view_transform.inverse() * light->transform).inverse(); + Transform proj = (p_view_transform.inverse() * p_refprobe2->transform).affine_inverse(); - CameraMatrix bias; - bias.set_light_bias(); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_LOCAL_MATRIX, proj); + } +} - CameraMatrix rectm; - rectm.set_light_atlas_rect(rect); +void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow) { - CameraMatrix shadow_matrix = rectm * bias * light->shadow_transform[0].camera * modelview; + ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, shadow_matrix); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); + Vector2 screen_pixel_size = state.screen_pixel_size; - } else { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0); - } + bool use_radiance_map = false; + if (!p_shadow && p_base_env) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); + glBindTexture(GL_TEXTURE_CUBE_MAP, p_base_env); + use_radiance_map = true; + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, true); //since prev unshaded is false, this needs to be true if exists + } - } break; + bool prev_unshaded = false; + bool prev_instancing = false; + state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); + RasterizerStorageGLES2::Material *prev_material = NULL; + RasterizerStorageGLES2::Geometry *prev_geometry = NULL; + RasterizerStorageGLES2::Skeleton *prev_skeleton = NULL; + RasterizerStorageGLES2::GeometryOwner *prev_owner = NULL; - default: break; - } + Transform view_transform_inverse = p_view_transform.inverse(); + CameraMatrix projection_inverse = p_projection.inverse(); - float energy = light->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - float specular = light->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + bool prev_base_pass = false; + LightInstance *prev_light = NULL; + bool prev_vertex_lit = false; + ReflectionProbeInstance *prev_refprobe_1 = NULL; + ReflectionProbeInstance *prev_refprobe_2 = NULL; - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ENERGY, energy); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, light->light_ptr->color.to_linear()); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular); + int prev_blend_mode = -2; //will always catch the first go - _render_geometry(e); - } + if (p_alpha_pass) { + glEnable(GL_BLEND); + } else { + glDisable(GL_BLEND); } - for (int dl = 0; dl < p_directional_light_count; dl++) { - RID light_rid = p_directional_lights[dl]; - LightInstance *light = light_instance_owner.getornull(light_rid); - RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; - - switch (light_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - } break; - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits); - } break; - - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true); - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits); - } break; - default: - break; - } + float fog_max_distance = 0; + bool using_fog = false; + if (p_env && !p_shadow && p_env->fog_enabled && (p_env->fog_depth_enabled || p_env->fog_height_enabled)) { + state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, p_env->fog_depth_enabled); + state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, p_env->fog_height_enabled); + fog_max_distance = p_projection.get_z_far(); + using_fog = true; + } - for (int i = 0; i < p_element_count; i++) { + RasterizerStorageGLES2::Texture *prev_lightmap = NULL; + float lightmap_energy = 1.0; + bool prev_use_lightmap_capture = false; - RenderList::Element *e = p_elements[i]; - RasterizerStorageGLES2::Material *material = e->material; - RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); + for (int i = 0; i < p_element_count; i++) { + RenderList::Element *e = p_elements[i]; - { - _setup_material(material, p_reverse_cull, false, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + RasterizerStorageGLES2::Material *material = e->material; - if (directional_shadow.depth) { - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); // TODO move into base pass - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + bool rebind = false; + bool accum_pass = *e->use_accum_ptr; + *e->use_accum_ptr = true; //set to accum for next time this is found + LightInstance *light = NULL; + ReflectionProbeInstance *refprobe_1 = NULL; + ReflectionProbeInstance *refprobe_2 = NULL; + RasterizerStorageGLES2::Texture *lightmap = NULL; + bool use_lightmap_capture = false; + bool rebind_light = false; + bool rebind_reflection = false; + bool rebind_lightmap = false; + + if (!p_shadow) { + + bool unshaded = material->shader->spatial.unshaded; + + if (unshaded != prev_unshaded) { + rebind = true; + if (unshaded) { + state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, true); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTING, false); + } else { + state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map); } - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse()); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); - state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse()); + prev_unshaded = unshaded; + } - state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + bool base_pass = !accum_pass && !unshaded; //conditions for a base pass - state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? - state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + if (base_pass != prev_base_pass) { + state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, base_pass); + rebind = true; + prev_base_pass = base_pass; } - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)0); - Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; + if (!unshaded && e->light_index < RenderList::MAX_LIGHTS) { + light = render_light_instances[e->light_index]; + } - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ENERGY, energy); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular); + if (light != prev_light) { - float sign = light_ptr->negative ? -1 : 1; + _setup_light_type(light, shadow_atlas); + rebind = true; + rebind_light = true; + } - Color linear_col = light_ptr->color.to_linear(); - Color color; - for (int c = 0; c < 3; c++) - color[c] = linear_col[c] * sign * energy * Math_PI; + int blend_mode = p_alpha_pass ? material->shader->spatial.blend_mode : -1; // -1 no blend, no mix - color[3] = 0; + if (accum_pass) { //accum pass force pass + blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD; + } - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, color); + if (prev_blend_mode != blend_mode) { - CameraMatrix matrices[4]; + if (prev_blend_mode == -1 && blend_mode != -1) { + //does blend + glEnable(GL_BLEND); + } else if (blend_mode == -1 && prev_blend_mode != -1) { + //do not blend + glDisable(GL_BLEND); + } - if (light_ptr->shadow && directional_shadow.depth) { + switch (blend_mode) { + //-1 not handled because not blend is enabled anyway + case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + } - int shadow_count = 0; - Color split_offsets; + } break; + case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD: { + + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(p_alpha_pass ? GL_SRC_ALPHA : GL_ONE, GL_ONE); - switch (light_ptr->directional_shadow_mode) { - case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: { - shadow_count = 1; } break; + case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB: { - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: { - shadow_count = 2; + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); } break; + case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MUL: { + glBlendEquation(GL_FUNC_ADD); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO); + } else { + glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE); + } - case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: { - shadow_count = 4; } break; } - for (int k = 0; k < shadow_count; k++) { + prev_blend_mode = blend_mode; + } - uint32_t x = light->directional_rect.position.x; - uint32_t y = light->directional_rect.position.y; - uint32_t width = light->directional_rect.size.x; - uint32_t height = light->directional_rect.size.y; + //condition to enable vertex lighting on this object + bool vertex_lit = (material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading) && ((!unshaded && light) || using_fog); //fog forces vertex lighting because it still applies even if unshaded or no fog - if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) { + if (vertex_lit != prev_vertex_lit) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit); + prev_vertex_lit = vertex_lit; + } - width /= 2; - height /= 2; + if (!unshaded && !accum_pass && e->refprobe_0_index != RenderList::MAX_REFLECTION_PROBES) { + ERR_FAIL_INDEX(e->refprobe_0_index, reflection_probe_count); + refprobe_1 = reflection_probe_instances[e->refprobe_0_index]; + } + if (!unshaded && !accum_pass && e->refprobe_1_index != RenderList::MAX_REFLECTION_PROBES) { + ERR_FAIL_INDEX(e->refprobe_1_index, reflection_probe_count); + refprobe_2 = reflection_probe_instances[e->refprobe_1_index]; + } - if (k == 0) { + if (refprobe_1 != prev_refprobe_1 || refprobe_2 != prev_refprobe_2) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, refprobe_1 != NULL); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, refprobe_2 != NULL); + if (refprobe_1 != NULL && refprobe_1 != prev_refprobe_1) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); + glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_1->cubemap); + } + if (refprobe_2 != NULL && refprobe_2 != prev_refprobe_2) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6); + glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_2->cubemap); + } + rebind = true; + rebind_reflection = true; + } - } else if (k == 1) { - x += width; - } else if (k == 2) { - y += height; - } else if (k == 3) { - x += width; - y += height; - } + use_lightmap_capture = !unshaded && !accum_pass && !e->instance->lightmap_capture_data.empty(); - } else if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) { + if (use_lightmap_capture != prev_use_lightmap_capture) { - height /= 2; + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, use_lightmap_capture); + rebind = true; + } - if (k == 0) { + if (!unshaded && !accum_pass && e->instance->lightmap.is_valid()) { - } else { - y += height; - } + lightmap = storage->texture_owner.getornull(e->instance->lightmap); + lightmap_energy = 1.0; + if (lightmap) { + RasterizerStorageGLES2::LightmapCapture *capture = storage->lightmap_capture_data_owner.getornull(e->instance->lightmap_capture->base); + if (capture) { + lightmap_energy = capture->energy; } + } + } - split_offsets[k] = light->shadow_transform[k].split; + if (lightmap != prev_lightmap) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, lightmap != NULL); + if (lightmap != NULL) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, lightmap->tex_id); + } + rebind = true; + rebind_lightmap = true; + } + } - Transform modelview = (p_view_transform * light->shadow_transform[k].transform).inverse(); + bool instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH; - CameraMatrix bias; - bias.set_light_bias(); - CameraMatrix rectm; - Rect2 atlas_rect = Rect2(float(x) / directional_shadow.size, float(y) / directional_shadow.size, float(width) / directional_shadow.size, float(height) / directional_shadow.size); - rectm.set_light_atlas_rect(atlas_rect); + if (instancing != prev_instancing) { - CameraMatrix shadow_mtx = rectm * bias * light->shadow_transform[k].camera * modelview; - matrices[k] = shadow_mtx.inverse(); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, instancing); + rebind = true; + } - Color light_clamp; - light_clamp[0] = atlas_rect.position.x; - light_clamp[1] = atlas_rect.position.y; - light_clamp[2] = atlas_rect.size.x; - light_clamp[3] = atlas_rect.size.y; + RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPLIT_OFFSETS, split_offsets); - } + if (skeleton != prev_skeleton) { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX1, matrices[0]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX2, matrices[1]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX3, matrices[2]); - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX4, matrices[3]); + if (skeleton) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, true); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, !storage->config.float_texture_supported); } else { - state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, false); } - _render_geometry(e); + rebind = true; + } + + if (e->owner != prev_owner || e->geometry != prev_geometry || skeleton != prev_skeleton) { + _setup_geometry(e, skeleton); } - } - state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false); + bool shader_rebind = false; + if (rebind || material != prev_material) { + shader_rebind = _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + } + + if (i == 0 || shader_rebind) { //first time must rebind + if (p_shadow) { + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_NORMAL_BIAS, p_shadow_normal_bias); + if (state.shadow_is_dual_parabolloid) { + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_DUAL_PARABOLOID_RENDER_SIDE, state.dual_parbolloid_direction); + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_DUAL_PARABOLOID_RENDER_ZFAR, state.dual_parbolloid_zfar); + } + } else { + if (use_radiance_map) { + state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform); + } + + if (p_env) { + state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution); + + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, p_env->ambient_energy); + + } else { + state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, 1.0); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, 1.0); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, Color(1.0, 1.0, 1.0, 1.0)); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0); + } + + //rebind all these + rebind_light = true; + rebind_reflection = true; + rebind_lightmap = true; + + if (using_fog) { + + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_COLOR_BASE, p_env->fog_color); + Color sun_color_amount = p_env->fog_sun_color; + sun_color_amount.a = p_env->fog_sun_amount; + + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_SUN_COLOR_AMOUNT, sun_color_amount); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_TRANSMIT_ENABLED, p_env->fog_transmit_enabled); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_TRANSMIT_CURVE, p_env->fog_transmit_curve); + + if (p_env->fog_depth_enabled) { + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_DEPTH_BEGIN, p_env->fog_depth_begin); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_DEPTH_CURVE, p_env->fog_depth_curve); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_MAX_DISTANCE, fog_max_distance); + } + + if (p_env->fog_height_enabled) { + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MIN, p_env->fog_height_min); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MAX, p_env->fog_height_max); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MAX, p_env->fog_height_max); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_CURVE, p_env->fog_height_curve); + } + } + } + + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform); + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, view_transform_inverse); + state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); + state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, projection_inverse); + + state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); + + state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); + state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? + } + + if (rebind_light && light) { + _setup_light(light, shadow_atlas, p_view_transform); + } + + if (rebind_reflection && (refprobe_1 || refprobe_2)) { + _setup_refprobes(refprobe_1, refprobe_2, p_view_transform, p_env); + } + + if (rebind_lightmap && lightmap) { + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_ENERGY, lightmap_energy); + } + + state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + + if (use_lightmap_capture) { //this is per instance, must be set always if present + glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES2::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr()); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_CAPTURE_SKY, false); + } + + _render_geometry(e); + + prev_geometry = e->geometry; + prev_owner = e->owner; + prev_material = material; + prev_skeleton = skeleton; + prev_instancing = instancing; + prev_light = light; + prev_refprobe_1 = refprobe_1; + prev_refprobe_2 = refprobe_2; + prev_lightmap = lightmap; + prev_use_lightmap_capture = use_lightmap_capture; + } + + _setup_light_type(NULL, NULL); //clear light stuff + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); + state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); + state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, false); + state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, false); + state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, false); } void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy) { @@ -1992,13 +2455,20 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C glEnableVertexAttribArray(VS::ARRAY_VERTEX); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, asymmetrical); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, !asymmetrical); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, true); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, true); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false); storage->shaders.copy.bind(); storage->shaders.copy.set_uniform(CopyShaderGLES2::MULTIPLIER, p_energy); + if (asymmetrical) { + // pack the bits we need from our projection matrix + storage->shaders.copy.set_uniform(CopyShaderGLES2::ASYM_PROJ, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1]); + ///@TODO I couldn't get mat3 + p_transform.basis to work, that would be better here. + storage->shaders.copy.set_uniform(CopyShaderGLES2::PANO_TRANSFORM, p_transform); + } glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -2006,16 +2476,92 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C glDisableVertexAttribArray(VS::ARRAY_TEX_UV); glBindBuffer(GL_ARRAY_BUFFER, 0); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); } void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { - glEnable(GL_BLEND); + GLuint current_fb = 0; + Environment *env = NULL; + + int viewport_width, viewport_height; + + if (p_reflection_probe.is_valid()) { + ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe); + ERR_FAIL_COND(!probe); + state.render_no_shadows = !probe->probe_ptr->enable_shadows; + + if (!probe->probe_ptr->interior) { //use env only if not interior + env = environment_owner.getornull(p_environment); + } + + current_fb = probe->fbo[p_reflection_probe_pass]; + state.screen_pixel_size.x = 1.0 / probe->probe_ptr->resolution; + state.screen_pixel_size.y = 1.0 / probe->probe_ptr->resolution; + + viewport_width = probe->probe_ptr->resolution; + viewport_height = probe->probe_ptr->resolution; + + } else { + state.render_no_shadows = false; + current_fb = storage->frame.current_rt->fbo; + env = environment_owner.getornull(p_environment); + state.screen_pixel_size.x = 1.0 / storage->frame.current_rt->width; + state.screen_pixel_size.y = 1.0 / storage->frame.current_rt->height; + viewport_width = storage->frame.current_rt->width; + viewport_height = storage->frame.current_rt->height; + } + //push back the directional lights + + if (p_light_cull_count) { + //harcoded limit of 256 lights + render_light_instance_count = MIN(RenderList::MAX_LIGHTS, p_light_cull_count); + render_light_instances = (LightInstance **)alloca(sizeof(LightInstance *) * render_light_instance_count); + render_directional_lights = 0; + + //doing this because directional lights are at the end, put them at the beginning + int index = 0; + for (int i = render_light_instance_count - 1; i >= 0; i--) { + RID light_rid = p_light_cull_result[i]; + + LightInstance *light = light_instance_owner.getornull(light_rid); + + if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) { + render_directional_lights++; + //as goin in reverse, directional lights are always first anyway + } + + light->light_index = index; + render_light_instances[index] = light; + + index++; + } + + } else { + render_light_instances = NULL; + render_directional_lights = 0; + render_light_instance_count = 0; + } + + if (p_reflection_probe_cull_count) { - GLuint current_fb = storage->frame.current_rt->fbo; - Environment *env = environment_owner.getornull(p_environment); + reflection_probe_instances = (ReflectionProbeInstance **)alloca(sizeof(ReflectionProbeInstance *) * p_reflection_probe_cull_count); + reflection_probe_count = p_reflection_probe_cull_count; + for (int i = 0; i < p_reflection_probe_cull_count; i++) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_cull_result[i]); + ERR_CONTINUE(!rpi); + rpi->last_pass = render_pass + 1; //will be incremented later + rpi->index = i; + reflection_probe_instances[i] = rpi; + } + + } else { + reflection_probe_instances = NULL; + reflection_probe_count = 0; + } // render list stuff @@ -2025,6 +2571,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const // other stuff glBindFramebuffer(GL_FRAMEBUFFER, current_fb); + glViewport(0, 0, viewport_width, viewport_height); glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); @@ -2068,34 +2615,22 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const } } - Vector<RID> directional_lights; - - for (int i = 0; i < p_light_cull_count; i++) { - RID light_rid = p_light_cull_result[i]; - - LightInstance *light = light_instance_owner.getornull(light_rid); - - if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) { - directional_lights.push_back(light_rid); - } - } - // render opaque things first render_list.sort_by_key(false); - _render_render_list(render_list.elements, render_list.element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false, false); + _render_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false); // alpha pass glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - render_list.sort_by_key(true); - _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false, false); + render_list.sort_by_depth(true); + + _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false); - glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); - // #define GLES2_SHADOW_ATLAS_DEBUG_VIEW + //#define GLES2_SHADOW_ATLAS_DEBUG_VIEW #ifdef GLES2_SHADOW_ATLAS_DEBUG_VIEW ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); @@ -2114,10 +2649,31 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const storage->_copy_screen(); } #endif + + //#define GLES2_SHADOW_DIRECTIONAL_DEBUG_VIEW + +#ifdef GLES2_SHADOW_DIRECTIONAL_DEBUG_VIEW + if (true) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + + glViewport(0, 0, storage->frame.current_rt->width / 4, storage->frame.current_rt->height / 4); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false); + storage->shaders.copy.bind(); + + storage->_copy_screen(); + } +#endif } void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { + state.render_no_shadows = false; + LightInstance *light_instance = light_instance_owner.getornull(p_light); ERR_FAIL_COND(!light_instance); @@ -2128,13 +2684,13 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ uint32_t y; uint32_t width; uint32_t height; - uint32_t vp_height; float zfar = 0; bool flip_facing = false; int custom_vp_size = 0; - GLuint fbo = 0; + state.shadow_is_dual_parabolloid = false; + state.dual_parbolloid_direction = 0.0; int current_cubemap = -1; float bias = 0; @@ -2213,14 +2769,12 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult; fbo = directional_shadow.fbo; - vp_height = directional_shadow.size; } else { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); fbo = shadow_atlas->fbo; - vp_height = shadow_atlas->size; uint32_t key = shadow_atlas->shadow_owners[p_light]; @@ -2263,8 +2817,32 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ zfar = light->param[VS::LIGHT_PARAM_RANGE]; current_cubemap = cubemap_index; + } else { + //dual parabolloid + state.shadow_is_dual_parabolloid = true; + light_projection = light_instance->shadow_transform[0].camera; + light_transform = light_instance->shadow_transform[0].transform; + + if (light->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) { + + height /= 2; + y += p_pass * height; + } else { + width /= 2; + x += p_pass * width; + } + + state.dual_parbolloid_direction = p_pass == 0 ? 1.0 : -1.0; + flip_facing = (p_pass == 1); + zfar = light->param[VS::LIGHT_PARAM_RANGE]; + bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS]; + + state.dual_parbolloid_zfar = zfar; + + state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH_DUAL_PARABOLOID, true); } - } else { + + } else if (light->type == VS::LIGHT_SPOT) { light_projection = light_instance->shadow_transform[0].camera; light_transform = light_instance->shadow_transform[0].transform; @@ -2303,11 +2881,16 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ glClear(GL_DEPTH_BUFFER_BIT); glDisable(GL_SCISSOR_TEST); + if (light->reverse_cull) { + flip_facing = !flip_facing; + } + state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, true); - _render_render_list(render_list.elements, render_list.element_count, NULL, 0, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, false, false, true, false); + _render_render_list(render_list.elements, render_list.element_count, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, flip_facing, false, true); state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, false); + state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH_DUAL_PARABOLOID, false); // convert cubemap to dual paraboloid if needed if (light->type == VS::LIGHT_OMNI && light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE && p_pass == 5) { @@ -2357,6 +2940,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ } glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + glColorMask(1, 1, 1, 1); } void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) { @@ -2364,6 +2948,44 @@ void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) { } bool RasterizerSceneGLES2::free(RID p_rid) { + + if (light_instance_owner.owns(p_rid)) { + + LightInstance *light_instance = light_instance_owner.getptr(p_rid); + + //remove from shadow atlases.. + for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(E->get()); + ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); + uint32_t key = shadow_atlas->shadow_owners[p_rid]; + uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; + uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; + + shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); + shadow_atlas->shadow_owners.erase(p_rid); + } + + light_instance_owner.free(p_rid); + memdelete(light_instance); + + } else if (shadow_atlas_owner.owns(p_rid)) { + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(p_rid); + shadow_atlas_set_size(p_rid, 0); + shadow_atlas_owner.free(p_rid); + memdelete(shadow_atlas); + } else if (reflection_probe_instance_owner.owns(p_rid)) { + + ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.get(p_rid); + + reflection_probe_release_atlas_index(p_rid); + reflection_probe_instance_owner.free(p_rid); + memdelete(reflection_instance); + + } else { + return false; + } + return true; } @@ -2376,6 +2998,8 @@ void RasterizerSceneGLES2::initialize() { render_list.init(); + render_pass = 1; + shadow_atlas_realloc_tolerance_msec = 500; { @@ -2393,6 +3017,27 @@ void RasterizerSceneGLES2::initialize() { } { + default_worldcoord_shader = storage->shader_create(); + storage->shader_set_code(default_worldcoord_shader, "shader_type spatial; render_mode world_vertex_coords;\n"); + default_worldcoord_material = storage->material_create(); + storage->material_set_shader(default_worldcoord_material, default_worldcoord_shader); + + default_worldcoord_shader_twosided = storage->shader_create(); + default_worldcoord_material_twosided = storage->material_create(); + storage->shader_set_code(default_worldcoord_shader_twosided, "shader_type spatial; render_mode cull_disabled,world_vertex_coords;\n"); + storage->material_set_shader(default_worldcoord_material_twosided, default_worldcoord_shader_twosided); + } + + { + //default material and shader + + default_overdraw_shader = storage->shader_create(); + storage->shader_set_code(default_overdraw_shader, "shader_type spatial;\nrender_mode blend_add,unshaded;\n void fragment() { ALBEDO=vec3(0.4,0.8,0.8); ALPHA=0.2; }"); + default_overdraw_material = storage->material_create(); + storage->material_set_shader(default_overdraw_material, default_overdraw_shader); + } + + { glGenBuffers(1, &state.sky_verts); glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, NULL, GL_DYNAMIC_DRAW); @@ -2401,6 +3046,7 @@ void RasterizerSceneGLES2::initialize() { { uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); glGenBuffers(1, &state.immediate_buffer); glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); @@ -2426,7 +3072,7 @@ void RasterizerSceneGLES2::initialize() { glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap); for (int i = 0; i < 6; i++) { - glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -2462,8 +3108,8 @@ void RasterizerSceneGLES2::initialize() { glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -2474,9 +3120,12 @@ void RasterizerSceneGLES2::initialize() { ERR_PRINT("Directional shadow framebuffer status invalid"); } } + + shadow_filter_mode = SHADOW_FILTER_NEAREST; } void RasterizerSceneGLES2::iteration() { + shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); } void RasterizerSceneGLES2::finalize() { diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 72dbe14387..33ac99366d 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -27,6 +27,7 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RASTERIZERSCENEGLES2_H #define RASTERIZERSCENEGLES2_H @@ -52,12 +53,39 @@ class RasterizerSceneGLES2 : public RasterizerScene { public: + enum ShadowFilterMode { + SHADOW_FILTER_NEAREST, + SHADOW_FILTER_PCF5, + SHADOW_FILTER_PCF13, + }; + + enum { + INSTANCE_ATTRIB_BASE = 8, + INSTANCE_BONE_BASE = 13, + }; + + ShadowFilterMode shadow_filter_mode; + RID default_material; RID default_material_twosided; RID default_shader; RID default_shader_twosided; + RID default_worldcoord_material; + RID default_worldcoord_material_twosided; + RID default_worldcoord_shader; + RID default_worldcoord_shader_twosided; + + RID default_overdraw_material; + RID default_overdraw_shader; + + uint64_t render_pass; uint64_t scene_pass; + uint32_t current_material_index; + uint32_t current_geometry_index; + uint32_t current_light_index; + uint32_t current_refprobe_index; + uint32_t current_shader_index; RasterizerStorageGLES2 *storage; struct State { @@ -171,11 +199,19 @@ public: bool cull_front; bool cull_disabled; bool used_sss; - bool used_screen_texture; bool using_contact_shadows; VS::ViewportDebugDraw debug_draw; */ + + bool used_screen_texture; + bool shadow_is_dual_parabolloid; + float dual_parbolloid_direction; + float dual_parbolloid_zfar; + + bool render_no_shadows; + + Vector2 screen_pixel_size; } state; /* SHADOW ATLAS API */ @@ -259,6 +295,38 @@ public: /* REFLECTION PROBE INSTANCE */ + struct ReflectionProbeInstance : public RID_Data { + + RasterizerStorageGLES2::ReflectionProbe *probe_ptr; + RID probe; + RID self; + RID atlas; + + int reflection_atlas_index; + + int render_step; + int reflection_index; + + GLuint fbo[6]; + GLuint cubemap; + GLuint depth; + + GLuint fbo_blur; + + int current_resolution; + mutable bool dirty; + + uint64_t last_pass; + uint32_t index; + + Transform transform; + }; + + mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; + + ReflectionProbeInstance **reflection_probe_instances; + int reflection_probe_count; + virtual RID reflection_probe_instance_create(RID p_probe); virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform); virtual void reflection_probe_release_atlas_index(RID p_instance); @@ -285,6 +353,21 @@ public: int canvas_max_layer; + bool fog_enabled; + Color fog_color; + Color fog_sun_color; + float fog_sun_amount; + + bool fog_depth_enabled; + float fog_depth_begin; + float fog_depth_curve; + bool fog_transmit_enabled; + float fog_transmit_curve; + bool fog_height_enabled; + float fog_height_min; + float fog_height_max; + float fog_height_curve; + Environment() { bg_mode = VS::ENV_BG_CLEAR_COLOR; sky_custom_fov = 0.0; @@ -293,6 +376,24 @@ public: ambient_energy = 1.0; ambient_sky_contribution = 0.0; canvas_max_layer = 0; + + fog_enabled = false; + fog_color = Color(0.5, 0.5, 0.5); + fog_sun_color = Color(0.8, 0.8, 0.0); + fog_sun_amount = 0; + + fog_depth_enabled = true; + + fog_depth_begin = 10; + fog_depth_curve = 1; + + fog_transmit_enabled = true; + fog_transmit_curve = 1; + + fog_height_enabled = false; + fog_height_min = 0; + fog_height_max = 100; + fog_height_curve = 1; } }; @@ -372,6 +473,10 @@ public: virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0); virtual void light_instance_mark_visible(RID p_light_instance); + LightInstance **render_light_instances; + int render_directional_lights; + int render_light_instance_count; + /* REFLECTION INSTANCE */ virtual RID gi_probe_instance_create(); @@ -381,40 +486,19 @@ public: /* RENDER LIST */ + enum LightMode { + LIGHTMODE_NORMAL, + LIGHTMODE_UNSHADED, + LIGHTMODE_LIGHTMAP, + LIGHTMODE_LIGHTMAP_CAPTURE, + }; + struct RenderList { + enum { - DEFAULT_MAX_ELEMENTS = 65536, - SORT_FLAG_SKELETON = 1, - SORT_FLAG_INSTANCING = 2, - MAX_DIRECTIONAL_LIGHTS = 16, - MAX_LIGHTS = 4096, - MAX_REFLECTIONS = 1024, - - SORT_KEY_PRIORITY_SHIFT = 56, - SORT_KEY_PRIORITY_MASK = 0xFF, - //depth layer for opaque (56-52) - SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT = 52, - SORT_KEY_OPAQUE_DEPTH_LAYER_MASK = 0xF, -//64 bits unsupported in MSVC -#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 49) -#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 48) -#define SORT_KEY_LIGHTMAP_CAPTURE_FLAG (uint64_t(1) << 47) -#define SORT_KEY_LIGHTMAP_FLAG (uint64_t(1) << 46) -#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 45) -#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 44) - SORT_KEY_SHADING_SHIFT = 44, - SORT_KEY_SHADING_MASK = 63, - //44-28 material index - SORT_KEY_MATERIAL_INDEX_SHIFT = 28, - //28-8 geometry index - SORT_KEY_GEOMETRY_INDEX_SHIFT = 8, - //bits 5-7 geometry type - SORT_KEY_GEOMETRY_TYPE_SHIFT = 5, - //bits 0-5 for flags - SORT_KEY_OPAQUE_PRE_PASS = 8, - SORT_KEY_CULL_DISABLED_FLAG = 4, - SORT_KEY_SKELETON_FLAG = 2, - SORT_KEY_MIRROR_FLAG = 1 + MAX_LIGHTS = 255, + MAX_REFLECTION_PROBES = 255, + DEFAULT_MAX_ELEMENTS = 65536 }; int max_elements; @@ -426,7 +510,38 @@ public: RasterizerStorageGLES2::Material *material; RasterizerStorageGLES2::GeometryOwner *owner; - uint64_t sort_key; + bool use_accum; //is this an add pass for multipass + bool *use_accum_ptr; + + union { + //TODO: should be endian swapped on big endian + struct { + int32_t depth_layer : 16; + int32_t priority : 16; + }; + + uint32_t depth_key; + }; + + union { + struct { + //from least significant to most significant in sort, TODO: should be endian swapped on big endian + + uint64_t geometry_index : 14; + uint64_t instancing : 1; + uint64_t skeleton : 1; + uint64_t shader_index : 10; + uint64_t material_index : 10; + uint64_t light_index : 8; + uint64_t light_type2 : 1; // if 1==0 : nolight/directional, else omni/spot + uint64_t refprobe_1_index : 8; + uint64_t refprobe_0_index : 8; + uint64_t light_type1 : 1; //no light, directional is 0, omni spot is 1 + uint64_t light_mode : 2; // LightMode enum + }; + + uint64_t sort_key; + }; }; Element *base_elements; @@ -444,7 +559,11 @@ public: struct SortByKey { _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->sort_key < B->sort_key; + if (A->depth_key == B->depth_key) { + return A->sort_key < B->sort_key; + } else { + return A->depth_key < B->depth_key; + } } }; @@ -475,29 +594,6 @@ public: } } - struct SortByReverseDepthAndPriority { - - _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - uint32_t layer_A = uint32_t(A->sort_key >> SORT_KEY_PRIORITY_SHIFT); - uint32_t layer_B = uint32_t(B->sort_key >> SORT_KEY_PRIORITY_SHIFT); - if (layer_A == layer_B) { - return A->instance->depth > B->instance->depth; - } else { - return layer_A < layer_B; - } - } - }; - - void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha - - SortArray<Element *, SortByReverseDepthAndPriority> sorter; - if (p_alpha) { - sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); - } else { - sorter.sort(elements, element_count); - } - } - // element adding and stuff _FORCE_INLINE_ Element *add_element() { @@ -548,7 +644,6 @@ public: void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass); void _render_render_list(RenderList::Element **p_elements, int p_element_count, - const RID *p_directional_lights, int p_directional_light_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, @@ -558,14 +653,16 @@ public: float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, - bool p_shadow, - bool p_directional_add); + bool p_shadow); void _draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy); - void _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0)); - void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); - void _render_geometry(RenderList::Element *p_element); + _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0)); + _FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); + _FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas); + _FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform); + _FORCE_INLINE_ void _setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env); + _FORCE_INLINE_ void _render_geometry(RenderList::Element *p_element); virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index 5b5ab987d1..c4c5093540 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -27,14 +27,13 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "rasterizer_storage_gles2.h" -#include "project_settings.h" +#include "core/math/transform.h" +#include "core/project_settings.h" #include "rasterizer_canvas_gles2.h" #include "rasterizer_scene_gles2.h" - -#include "math/transform.h" - #include "servers/visual/shader_language.h" GLuint RasterizerStorageGLES2::system_fbo = 0; @@ -53,6 +52,10 @@ GLuint RasterizerStorageGLES2::system_fbo = 0; #define _GL_HALF_FLOAT_OES 0x8D61 #endif +#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F + +#define _DEPTH_COMPONENT24_OES 0x81A6 + void RasterizerStorageGLES2::bind_quad_array() const { glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); @@ -355,7 +358,6 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ GLenum type; bool compressed = false; - bool srgb = false; if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { p_flags &= ~VS::TEXTURE_FLAG_MIPMAPS; // no mipies for video @@ -496,22 +498,6 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } -//set swizle for older format compatibility -#ifdef GLES_OVER_GL - switch (texture->format) { - - case Image::FORMAT_L8: { - - } break; - case Image::FORMAT_LA8: { - - } break; - default: { - - } break; - } -#endif - int mipmaps = ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; int w = img->get_width(); @@ -591,7 +577,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) PoolVector<uint8_t> data; - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1 ? -1 : 0); + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers PoolVector<uint8_t>::Write wb = data.write(); @@ -627,8 +613,72 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) return Ref<Image>(img); #else - ERR_EXPLAIN("Sorry, It's not possible to obtain images back in OpenGL ES"); - ERR_FAIL_V(Ref<Image>()); + Image::Format real_format; + GLenum gl_format; + GLenum gl_internal_format; + GLenum gl_type; + bool compressed; + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed); + + PoolVector<uint8_t> data; + + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); + + data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers + PoolVector<uint8_t>::Write wb = data.write(); + + GLuint temp_framebuffer; + glGenFramebuffers(1, &temp_framebuffer); + + GLuint temp_color_texture; + glGenTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + + glBindTexture(GL_TEXTURE_2D, temp_color_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1, 1, 1, 1); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + + glViewport(0, 0, texture->alloc_width, texture->alloc_height); + + shaders.copy.bind(); + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + bind_quad_array(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); + + glDeleteTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &temp_framebuffer); + + wb = PoolVector<uint8_t>::Write(); + + data.resize(data_size); + + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); + if (!texture->compressed) { + img->convert(real_format); + } + + return Ref<Image>(img); + #endif } @@ -915,26 +965,27 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra // attachements for it, so we can fill them by issuing draw calls. GLuint tmp_fb; - glGenFramebuffers(1, &tmp_fb); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - int size = p_radiance_size; int lod = 0; - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, texture->target == GL_TEXTURE_2D); - - shaders.cubemap_filter.bind(); - int mipmaps = 6; int mm_level = mipmaps; - GLenum internal_format = GL_RGBA; - GLenum format = GL_RGBA; - GLenum type = GL_UNSIGNED_BYTE; // This is suboptimal... TODO other format for FBO? + GLenum internal_format = GL_RGB; + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; // Set the initial (empty) mipmaps +#if 1 + //Mobile hardware (PowerVR specially) prefers this approach, the other one kills the game + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL); + } + + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); +#else while (size >= 1) { for (int i = 0; i < 6; i++) { @@ -945,7 +996,14 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra size >>= 1; } +#endif + //framebuffer + glGenFramebuffers(1, &tmp_fb); + glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, texture->target == GL_TEXTURE_2D); + + shaders.cubemap_filter.bind(); lod = 0; mm_level = mipmaps; @@ -964,6 +1022,7 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); float roughness = mm_level ? lod / (float)(mipmaps - 1) : 1; + roughness = MIN(1.0, roughness); //keep max at 1 shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -1309,8 +1368,13 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn pi.hint_string = "CubeMap"; } break; - default: { - + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in GLES2 } break; } @@ -1420,6 +1484,19 @@ Variant RasterizerStorageGLES2::material_get_param(RID p_material, const StringN return material->params[p_param]; } + return material_get_param_default(p_material, p_param); +} + +Variant RasterizerStorageGLES2::material_get_param_default(RID p_material, const StringName &p_param) const { + const Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material, Variant()); + + if (material->shader) { + if (material->shader->uniforms.has(p_param)) { + Vector<ShaderLanguage::ConstantNode::Value> default_value = material->shader->uniforms[p_param].default_value; + return ShaderLanguage::constant_value_to_variant(default_value, material->shader->uniforms[p_param].type); + } + } return Variant(); } @@ -1552,7 +1629,7 @@ void RasterizerStorageGLES2::_update_material(Material *p_material) { } } - // uniforms and other thigns will be set in the use_material method in ShaderGLES2 + // uniforms and other things will be set in the use_material method in ShaderGLES2 if (p_material->shader && p_material->shader->texture_count > 0) { @@ -2622,10 +2699,10 @@ void RasterizerStorageGLES2::update_dirty_multimeshes() { if (multimesh->mesh.is_valid()) { mesh_aabb = mesh_get_aabb(multimesh->mesh, RID()); - } else { - mesh_aabb.size += Vector3(0.001, 0.001, 0.001); } + mesh_aabb.size += Vector3(0.001, 0.001, 0.001); //in case mesh is empty in one of the sides + int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; int count = multimesh->data.size(); float *data = multimesh->data.ptrw(); @@ -3097,6 +3174,7 @@ void RasterizerStorageGLES2::light_set_param(RID p_light, VS::LightParam p_param light->version++; light->instance_change_notify(); } break; + default: {} } light->param[p_param] = p_value; @@ -3148,6 +3226,9 @@ void RasterizerStorageGLES2::light_set_reverse_cull_face_mode(RID p_light, bool ERR_FAIL_COND(!light); light->reverse_cull = p_enabled; + + light->version++; + light->instance_change_notify(); } void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) { @@ -3288,69 +3369,194 @@ AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const { /* PROBE API */ RID RasterizerStorageGLES2::reflection_probe_create() { - return RID(); + + ReflectionProbe *reflection_probe = memnew(ReflectionProbe); + + reflection_probe->intensity = 1.0; + reflection_probe->interior_ambient = Color(); + reflection_probe->interior_ambient_energy = 1.0; + reflection_probe->max_distance = 0; + reflection_probe->extents = Vector3(1, 1, 1); + reflection_probe->origin_offset = Vector3(0, 0, 0); + reflection_probe->interior = false; + reflection_probe->box_projection = false; + reflection_probe->enable_shadows = false; + reflection_probe->cull_mask = (1 << 20) - 1; + reflection_probe->update_mode = VS::REFLECTION_PROBE_UPDATE_ONCE; + reflection_probe->resolution = 128; + + return reflection_probe_owner.make_rid(reflection_probe); } void RasterizerStorageGLES2::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->update_mode = p_mode; + reflection_probe->instance_change_notify(); } void RasterizerStorageGLES2::reflection_probe_set_intensity(RID p_probe, float p_intensity) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->intensity = p_intensity; } void RasterizerStorageGLES2::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient = p_ambient; } void RasterizerStorageGLES2::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_energy = p_energy; } void RasterizerStorageGLES2::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_probe_contrib = p_contrib; } void RasterizerStorageGLES2::reflection_probe_set_max_distance(RID p_probe, float p_distance) { -} -void RasterizerStorageGLES2::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->max_distance = p_distance; + reflection_probe->instance_change_notify(); } +void RasterizerStorageGLES2::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->extents = p_extents; + reflection_probe->instance_change_notify(); +} void RasterizerStorageGLES2::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->origin_offset = p_offset; + reflection_probe->instance_change_notify(); } void RasterizerStorageGLES2::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { -} + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior = p_enable; +} void RasterizerStorageGLES2::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->box_projection = p_enable; } void RasterizerStorageGLES2::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { -} + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->enable_shadows = p_enable; + reflection_probe->instance_change_notify(); +} void RasterizerStorageGLES2::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->cull_mask = p_layers; + reflection_probe->instance_change_notify(); +} + +void RasterizerStorageGLES2::reflection_probe_set_resolution(RID p_probe, int p_resolution) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->resolution = p_resolution; } AABB RasterizerStorageGLES2::reflection_probe_get_aabb(RID p_probe) const { - return AABB(); + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, AABB()); + + AABB aabb; + aabb.position = -reflection_probe->extents; + aabb.size = reflection_probe->extents * 2.0; + + return aabb; } VS::ReflectionProbeUpdateMode RasterizerStorageGLES2::reflection_probe_get_update_mode(RID p_probe) const { - return VS::REFLECTION_PROBE_UPDATE_ALWAYS; + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, VS::REFLECTION_PROBE_UPDATE_ALWAYS); + + return reflection_probe->update_mode; } uint32_t RasterizerStorageGLES2::reflection_probe_get_cull_mask(RID p_probe) const { - return 0; + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->cull_mask; } Vector3 RasterizerStorageGLES2::reflection_probe_get_extents(RID p_probe) const { - return Vector3(); + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, Vector3()); + + return reflection_probe->extents; } Vector3 RasterizerStorageGLES2::reflection_probe_get_origin_offset(RID p_probe) const { - return Vector3(); + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, Vector3()); + + return reflection_probe->origin_offset; } bool RasterizerStorageGLES2::reflection_probe_renders_shadows(RID p_probe) const { - return false; + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, false); + + return reflection_probe->enable_shadows; } float RasterizerStorageGLES2::reflection_probe_get_origin_max_distance(RID p_probe) const { - return 0; + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->max_distance; +} + +int RasterizerStorageGLES2::reflection_probe_get_resolution(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->resolution; } RID RasterizerStorageGLES2::gi_probe_create() { @@ -3451,46 +3657,100 @@ void RasterizerStorageGLES2::gi_probe_dynamic_data_update(RID p_gi_probe_data, i /////// RID RasterizerStorageGLES2::lightmap_capture_create() { - return RID(); + + LightmapCapture *capture = memnew(LightmapCapture); + return lightmap_capture_data_owner.make_rid(capture); } void RasterizerStorageGLES2::lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) { -} -AABB RasterizerStorageGLES2::lightmap_capture_get_bounds(RID p_capture) const { - return AABB(); + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->bounds = p_bounds; + capture->instance_change_notify(); } +AABB RasterizerStorageGLES2::lightmap_capture_get_bounds(RID p_capture) const { -void RasterizerStorageGLES2::lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) { + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, AABB()); + return capture->bounds; } +void RasterizerStorageGLES2::lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) { + + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + + ERR_FAIL_COND(p_octree.size() == 0 || (p_octree.size() % sizeof(LightmapCaptureOctree)) != 0); + capture->octree.resize(p_octree.size() / sizeof(LightmapCaptureOctree)); + if (p_octree.size()) { + PoolVector<LightmapCaptureOctree>::Write w = capture->octree.write(); + PoolVector<uint8_t>::Read r = p_octree.read(); + copymem(w.ptr(), r.ptr(), p_octree.size()); + } + capture->instance_change_notify(); +} PoolVector<uint8_t> RasterizerStorageGLES2::lightmap_capture_get_octree(RID p_capture) const { - return PoolVector<uint8_t>(); + + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, PoolVector<uint8_t>()); + + if (capture->octree.size() == 0) + return PoolVector<uint8_t>(); + + PoolVector<uint8_t> ret; + ret.resize(capture->octree.size() * sizeof(LightmapCaptureOctree)); + { + PoolVector<LightmapCaptureOctree>::Read r = capture->octree.read(); + PoolVector<uint8_t>::Write w = ret.write(); + copymem(w.ptr(), r.ptr(), ret.size()); + } + + return ret; } void RasterizerStorageGLES2::lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) { + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->cell_xform = p_xform; } Transform RasterizerStorageGLES2::lightmap_capture_get_octree_cell_transform(RID p_capture) const { - return Transform(); + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, Transform()); + return capture->cell_xform; } void RasterizerStorageGLES2::lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) { + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->cell_subdiv = p_subdiv; } int RasterizerStorageGLES2::lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { - return 0; + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, 0); + return capture->cell_subdiv; } void RasterizerStorageGLES2::lightmap_capture_set_energy(RID p_capture, float p_energy) { + + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->energy = p_energy; } float RasterizerStorageGLES2::lightmap_capture_get_energy(RID p_capture) const { - return 0.0; + + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, 0); + return capture->energy; } const PoolVector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES2::lightmap_capture_get_octree_ptr(RID p_capture) const { - return NULL; + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, NULL); + return &capture->octree; } /////// @@ -3582,15 +3842,115 @@ void RasterizerStorageGLES2::update_particles() { //////// void RasterizerStorageGLES2::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + + skeleton->instances.insert(p_instance); } void RasterizerStorageGLES2::instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + + skeleton->instances.erase(p_instance); } void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { + + Instantiable *inst = NULL; + switch (p_instance->base_type) { + case VS::INSTANCE_MESH: { + inst = mesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_MULTIMESH: { + inst = multimesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_IMMEDIATE: { + inst = immediate_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + /*case VS::INSTANCE_PARTICLES: { + inst = particles_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break;*/ + case VS::INSTANCE_REFLECTION_PROBE: { + inst = reflection_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_LIGHT: { + inst = light_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + /*case VS::INSTANCE_GI_PROBE: { + inst = gi_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break;*/ + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + inst = lightmap_capture_data_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + default: { + if (!inst) { + ERR_FAIL(); + } + } + } + + inst->instance_list.add(&p_instance->dependency_item); } void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { + + Instantiable *inst = NULL; + + switch (p_instance->base_type) { + case VS::INSTANCE_MESH: { + inst = mesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_MULTIMESH: { + inst = multimesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_IMMEDIATE: { + inst = immediate_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + /*case VS::INSTANCE_PARTICLES: { + inst = particles_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break;*/ + case VS::INSTANCE_REFLECTION_PROBE: { + inst = reflection_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_LIGHT: { + inst = light_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + /*case VS::INSTANCE_GI_PROBE: { + inst = gi_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; */ + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + inst = lightmap_capture_data_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + default: { + + if (!inst) { + ERR_FAIL(); + } + } + } + + ERR_FAIL_COND(!inst); + + inst->instance_list.remove(&p_instance->dependency_item); } /* RENDER TARGET */ @@ -3632,7 +3992,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { glGenRenderbuffers(1, &rt->depth); glBindRenderbuffer(GL_RENDERBUFFER, rt->depth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, rt->width, rt->height); + glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, rt->width, rt->height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -3848,6 +4208,10 @@ VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const { return VS::INSTANCE_MULTIMESH; } else if (immediate_owner.owns(p_rid)) { return VS::INSTANCE_IMMEDIATE; + } else if (reflection_probe_owner.owns(p_rid)) { + return VS::INSTANCE_REFLECTION_PROBE; + } else if (lightmap_capture_data_owner.owns(p_rid)) { + return VS::INSTANCE_LIGHTMAP_CAPTURE; } else { return VS::INSTANCE_NONE; } @@ -4025,6 +4389,25 @@ bool RasterizerStorageGLES2::free(RID p_rid) { memdelete(light); return true; + } else if (reflection_probe_owner.owns(p_rid)) { + + // delete the texture + ReflectionProbe *reflection_probe = reflection_probe_owner.get(p_rid); + reflection_probe->instance_remove_deps(); + + reflection_probe_owner.free(p_rid); + memdelete(reflection_probe); + + return true; + } else if (lightmap_capture_data_owner.owns(p_rid)) { + + // delete the texture + LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid); + lightmap_capture->instance_remove_deps(); + + lightmap_capture_data_owner.free(p_rid); + memdelete(lightmap_capture); + return true; } else { return false; } @@ -4076,15 +4459,15 @@ void RasterizerStorageGLES2::initialize() { } config.shrink_textures_x2 = false; - config.float_texture_supported = config.extensions.find("GL_ARB_texture_float") != NULL || config.extensions.find("GL_OES_texture_float") != NULL; - config.s3tc_supported = config.extensions.find("GL_EXT_texture_compression_s3tc") != NULL; - config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") != NULL; + + config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); + config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc"); + config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); frame.count = 0; frame.delta = 0; frame.current_rt = NULL; frame.clear_request = false; - // config.keep_original_textures = false; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); @@ -4187,13 +4570,13 @@ void RasterizerStorageGLES2::initialize() { // radical inverse vdc cache texture // used for cubemap filtering - if (config.float_texture_supported) { + if (true /*||config.float_texture_supported*/) { //uint8 is similar and works everywhere glGenTextures(1, &resources.radical_inverse_vdc_cache_tex); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, resources.radical_inverse_vdc_cache_tex); - float radical_inverse[512]; + uint8_t radical_inverse[512]; for (uint32_t i = 0; i < 512; i++) { uint32_t bits = i; @@ -4205,14 +4588,23 @@ void RasterizerStorageGLES2::initialize() { bits = ((bits & 0x00FF00FF) << 8) | ((bits & 0xFF00FF00) >> 8); float value = float(bits) * 2.3283064365386963e-10; - - radical_inverse[i] = value; + radical_inverse[i] = uint8_t(CLAMP(value * 255.0, 0, 255)); } - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_FLOAT, radical_inverse); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, radical_inverse); glBindTexture(GL_TEXTURE_2D, 0); } + +#ifdef GLES_OVER_GL + //this needs to be enabled manually in OpenGL 2.1 + + glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); +#endif + + config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); } void RasterizerStorageGLES2::finalize() { @@ -4227,6 +4619,7 @@ void RasterizerStorageGLES2::update_dirty_resources() { update_dirty_shaders(); update_dirty_materials(); update_dirty_skeletons(); + update_dirty_multimeshes(); } RasterizerStorageGLES2::RasterizerStorageGLES2() { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index 88783d7160..c928f753b1 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -27,11 +27,12 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef RASTERIZERSTORAGEGLES2_H #define RASTERIZERSTORAGEGLES2_H -#include "dvector.h" -#include "self_list.h" +#include "core/dvector.h" +#include "core/self_list.h" #include "servers/visual/rasterizer.h" #include "servers/visual/shader_language.h" #include "shader_compiler_gles2.h" @@ -42,7 +43,6 @@ /* #include "shaders/blend_shape.glsl.gen.h" #include "shaders/canvas.glsl.gen.h" -#include "shaders/copy.glsl.gen.h" #include "shaders/particles.glsl.gen.h" */ @@ -156,7 +156,7 @@ public: //////////////////////////////////DATA/////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// - struct Instanciable : public RID_Data { + struct Instantiable : public RID_Data { SelfList<RasterizerScene::InstanceBase>::List instance_list; _FORCE_INLINE_ void instance_change_notify() { @@ -186,15 +186,15 @@ public: } } - Instanciable() {} + Instantiable() {} - virtual ~Instanciable() {} + virtual ~Instantiable() {} }; - struct GeometryOwner : public Instanciable { + struct GeometryOwner : public Instantiable { }; - struct Geometry : public Instanciable { + struct Geometry : public Instantiable { enum Type { GEOMETRY_INVALID, @@ -405,6 +405,9 @@ public: String path; + uint32_t index; + uint64_t last_pass; + struct CanvasItem { enum BlendMode { @@ -490,6 +493,7 @@ public: valid = false; custom_code_id = 0; version = 1; + last_pass = 0; } }; @@ -562,6 +566,7 @@ public: virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value); virtual Variant material_get_param(RID p_material, const StringName &p_param) const; + virtual Variant material_get_param_default(RID p_material, const StringName &p_param) const; virtual void material_set_line_width(RID p_material, float p_width); virtual void material_set_next_pass(RID p_material, RID p_next_material); @@ -887,7 +892,7 @@ public: /* Light API */ - struct Light : Instanciable { + struct Light : Instantiable { VS::LightType type; float param[VS::LIGHT_PARAM_MAX]; @@ -949,6 +954,26 @@ public: virtual uint64_t light_get_version(RID p_light) const; /* PROBE API */ + + struct ReflectionProbe : Instantiable { + + VS::ReflectionProbeUpdateMode update_mode; + float intensity; + Color interior_ambient; + float interior_ambient_energy; + float interior_ambient_probe_contrib; + float max_distance; + Vector3 extents; + Vector3 origin_offset; + bool interior; + bool box_projection; + bool enable_shadows; + uint32_t cull_mask; + int resolution; + }; + + mutable RID_Owner<ReflectionProbe> reflection_probe_owner; + virtual RID reflection_probe_create(); virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode); @@ -963,11 +988,14 @@ public: virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); + virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); virtual AABB reflection_probe_get_aabb(RID p_probe) const; virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const; + virtual int reflection_probe_get_resolution(RID p_probe) const; + virtual Vector3 reflection_probe_get_extents(RID p_probe) const; virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const; virtual float reflection_probe_get_origin_max_distance(RID p_probe) const; @@ -1017,6 +1045,21 @@ public: /* LIGHTMAP */ + struct LightmapCapture : public Instantiable { + + PoolVector<LightmapCaptureOctree> octree; + AABB bounds; + Transform cell_xform; + int cell_subdiv; + float energy; + LightmapCapture() { + energy = 1.0; + cell_subdiv = 1; + } + }; + + mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner; + virtual RID lightmap_capture_create(); virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds); virtual AABB lightmap_capture_get_bounds(RID p_capture) const; diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index 1c87b3ffb5..082c520480 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -27,11 +27,13 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #include "shader_compiler_gles2.h" -#include "os/os.h" -#include "string_buffer.h" -#include "string_builder.h" +#include "core/os/os.h" +#include "core/project_settings.h" +#include "core/string_buffer.h" +#include "core/string_builder.h" #define SL ShaderLanguage @@ -641,11 +643,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener case SL::OP_MOD: { - code += "mod("; + code += "mod(float("; code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ", "; + code += "), float("; code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")"; + code += "))"; } break; default: { @@ -829,6 +831,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize"; // gl_InstanceID is not available in OpenGL ES 2.0 actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0"; + actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; //builtins @@ -899,16 +902,30 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); + + if (!force_lambert) { + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); + + if (!force_blinn) { + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n"; /* PARTICLES SHADER */ diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index 804ead2172..5e9e295204 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -27,16 +27,16 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SHADERCOMPILERGLES2_H #define SHADERCOMPILERGLES2_H -#include "pair.h" +#include "core/pair.h" +#include "core/string_builder.h" #include "servers/visual/shader_language.h" #include "servers/visual/shader_types.h" #include "servers/visual_server.h" -#include "string_builder.h" - class ShaderCompilerGLES2 { public: struct IdentifierActions { diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index 3b2a29d3ee..628a57c06d 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -27,12 +27,12 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "shader_gles2.h" -#include "memory.h" -#include "print_string.h" -#include "string_builder.h" +#include "shader_gles2.h" +#include "core/os/memory.h" +#include "core/print_string.h" +#include "core/string_builder.h" #include "rasterizer_gles2.h" #include "rasterizer_storage_gles2.h" @@ -57,7 +57,7 @@ ShaderGLES2 *ShaderGLES2::active = NULL; -// #define DEBUG_SHADER +//#define DEBUG_SHADER #ifdef DEBUG_SHADER @@ -132,6 +132,11 @@ bool ShaderGLES2::bind() { ERR_FAIL_COND_V(!version, false); + if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation). + glUseProgram(0); + return false; + } + glUseProgram(version->id); // find out uniform names and locations @@ -171,72 +176,24 @@ void ShaderGLES2::unbind() { active = NULL; } -static String _fix_error_code_line(const String &p_error, int p_code_start, int p_offset) { - - int last_find_pos = -1; - // NVIDIA - String error = p_error; - while ((last_find_pos = p_error.find("(", last_find_pos + 1)) != -1) { - - int end_pos = last_find_pos + 1; - - while (true) { +static void _display_error_with_code(const String &p_error, const Vector<const char *> &p_code) { - if (p_error[end_pos] >= '0' && p_error[end_pos] <= '9') { - - end_pos++; - continue; - } else if (p_error[end_pos] == ')') { - break; - } else { - - end_pos = -1; - break; - } - } - - if (end_pos == -1) - continue; + int line = 1; + String total_code; - String numstr = error.substr(last_find_pos + 1, (end_pos - last_find_pos) - 1); - String begin = error.substr(0, last_find_pos + 1); - String end = error.substr(end_pos, error.length()); - int num = numstr.to_int() + p_code_start - p_offset; - error = begin + itos(num) + end; + for (int i = 0; i < p_code.size(); i++) { + total_code += String(p_code[i]); } - // ATI - last_find_pos = -1; - while ((last_find_pos = p_error.find("ERROR: ", last_find_pos + 1)) != -1) { + Vector<String> lines = String(total_code).split("\n"); - last_find_pos += 6; - int end_pos = last_find_pos + 1; + for (int j = 0; j < lines.size(); j++) { - while (true) { - - if (p_error[end_pos] >= '0' && p_error[end_pos] <= '9') { - - end_pos++; - continue; - } else if (p_error[end_pos] == ':') { - break; - } else { - - end_pos = -1; - break; - } - } - continue; - if (end_pos == -1) - continue; - - String numstr = error.substr(last_find_pos + 1, (end_pos - last_find_pos) - 1); - String begin = error.substr(0, last_find_pos + 1); - String end = error.substr(end_pos, error.length()); - int num = numstr.to_int() + p_code_start - p_offset; - error = begin + itos(num) + end; + print_line(itos(line) + ": " + lines[j]); + line++; } - return error; + + ERR_PRINTS(p_error); } ShaderGLES2::Version *ShaderGLES2::get_current_version() { @@ -293,7 +250,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { } } - // keep them around during the functino + // keep them around during the function CharString code_string; CharString code_string2; CharString code_globals; @@ -316,7 +273,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { if (cc) { for (int i = 0; i < cc->custom_defines.size(); i++) { strings.push_back(cc->custom_defines.write[i]); - DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i])); + DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i].get_data())); } } @@ -375,9 +332,8 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { String err_string = get_shader_name() + ": Vertex shader compilation failed:\n"; err_string += ilogmem; - err_string = _fix_error_code_line(err_string, vertex_code_start, define_line_ofs); - ERR_PRINTS(err_string); + _display_error_with_code(err_string, strings); Memory::free_static(ilogmem); glDeleteShader(v.vert_id); @@ -451,9 +407,8 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { String err_string = get_shader_name() + ": Fragment shader compilation failed:\n"; err_string += ilogmem; - err_string = _fix_error_code_line(err_string, fragment_code_start, define_line_ofs); - ERR_PRINTS(err_string); + _display_error_with_code(err_string, strings); Memory::free_static(ilogmem); glDeleteShader(v.frag_id); @@ -503,9 +458,8 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { String err_string = get_shader_name() + ": Program linking failed:\n"; err_string += ilogmem; - err_string = _fix_error_code_line(err_string, fragment_code_start, define_line_ofs); - ERR_PRINTS(err_string); + _display_error_with_code(err_string, strings); Memory::free_static(ilogmem); glDeleteShader(v.frag_id); @@ -736,11 +690,6 @@ void ShaderGLES2::use_material(void *p_material) { Version *v = version_map.getptr(conditional_version); - CustomCode *cc = NULL; - if (v) { - cc = custom_code_map.getptr(v->code_version); - } - // bind uniforms for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) { @@ -1028,7 +977,7 @@ void ShaderGLES2::use_material(void *p_material) { value.second.resize(default_arg_size); - for (int i = 0; i < default_arg_size; i++) { + for (size_t i = 0; i < default_arg_size; i++) { if (is_float) { value.second.write[i].real = 0.0; } else { @@ -1038,8 +987,6 @@ void ShaderGLES2::use_material(void *p_material) { } } - // GLint location = get_uniform_location(E->key()); - GLint location; if (v->custom_uniform_locations.has(E->key())) { location = v->custom_uniform_locations[E->key()]; @@ -1059,8 +1006,6 @@ void ShaderGLES2::use_material(void *p_material) { int tc = material->textures.size(); Pair<StringName, RID> *textures = material->textures.ptrw(); - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = material->shader->texture_hints.ptrw(); - for (int i = 0; i < tc; i++) { Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > value; diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h index cb515c199c..9160a7c265 100644 --- a/drivers/gles2/shader_gles2.h +++ b/drivers/gles2/shader_gles2.h @@ -27,11 +27,11 @@ /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ + #ifndef SHADER_GLES2_H #define SHADER_GLES2_H -#include <stdio.h> - +// This must come first to avoid windows.h mess #include "platform_config.h" #ifndef GLES2_INCLUDE_H #include <GLES2/gl2.h> @@ -39,14 +39,15 @@ #include GLES2_INCLUDE_H #endif -#include "camera_matrix.h" -#include "hash_map.h" -#include "map.h" -#include "variant.h" - +#include "core/hash_map.h" +#include "core/map.h" +#include "core/math/camera_matrix.h" #include "core/pair.h" +#include "core/variant.h" #include "servers/visual/shader_language.h" +#include <stdio.h> + class RasterizerStorageGLES2; class ShaderGLES2 { @@ -334,6 +335,19 @@ public: case ShaderLanguage::TYPE_SAMPLERCUBE: { } break; + + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in GLES2 + } break; + + case ShaderLanguage::TYPE_VOID: { + // Nothing to do? + } break; } } @@ -467,7 +481,8 @@ public: // like forward declared nested classes. void use_material(void *p_material); - uint32_t get_version() const { return new_conditional_version.version; } + _FORCE_INLINE_ uint32_t get_version() const { return new_conditional_version.version; } + _FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; } void set_uniform_camera(int p_idx, const CameraMatrix &p_mat) { diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub index acb93fff8f..d959d3f740 100644 --- a/drivers/gles2/shaders/SCsub +++ b/drivers/gles2/shaders/SCsub @@ -20,3 +20,4 @@ if 'GLES2_GLSL' in env['BUILDERS']: # env.GLES2_GLSL('exposure.glsl'); # env.GLES2_GLSL('tonemap.glsl'); # env.GLES2_GLSL('particles.glsl'); + env.GLES2_GLSL('lens_distorted.glsl'); diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index ba69ca9b6e..79d4eb2243 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -89,9 +89,18 @@ VERTEX_SHADER_CODE /* clang-format on */ } +#if !defined(SKIP_TRANSFORM_USED) + outvec = extra_matrix * outvec; + outvec = modelview_matrix * outvec; +#endif + color_interp = color; - gl_Position = projection_matrix * modelview_matrix * outvec; +#ifdef USE_PIXEL_SNAP + outvec.xy = floor(outvec + 0.5).xy; +#endif + + gl_Position = projection_matrix * outvec; } /* clang-format off */ @@ -139,7 +148,10 @@ void main() { vec4 color = color_interp; +#if !defined(COLOR_USED) + //default behavior, texture by color color *= texture2D(color_texture, uv_interp); +#endif #ifdef SCREEN_UV_USED vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl index 16bbde196d..0b8da4f875 100644 --- a/drivers/gles2/shaders/copy.glsl +++ b/drivers/gles2/shaders/copy.glsl @@ -35,6 +35,8 @@ void main() { #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) cube_interp = cube_in; +#elif defined(USE_ASYM_PANO) + uv_interp = vertex_attrib.xy; #else uv_interp = uv_in; #endif @@ -68,6 +70,11 @@ varying vec2 uv_interp; #endif /* clang-format on */ +#ifdef USE_ASYM_PANO +uniform highp mat4 pano_transform; +uniform highp vec4 asym_proj; +#endif + #ifdef USE_CUBEMAP uniform samplerCube source_cube; // texunit:0 #else @@ -108,6 +115,21 @@ void main() { vec4 color = texturePanorama(source, normalize(cube_interp)); +#elif defined(USE_ASYM_PANO) + + // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. + // Note that we're ignoring the x-offset for IPD, with Z sufficiently in the distance it becomes neglectible, as a result we could probably just set cube_normal.z to -1. + // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. + + vec3 cube_normal; + cube_normal.z = -1000000.0; + cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; + cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; + cube_normal = mat3(pano_transform) * cube_normal; + cube_normal.z = -cube_normal.z; + + vec4 color = texturePanorama(source, normalize(cube_normal.xyz)); + #elif defined(USE_CUBEMAP) vec4 color = textureCube(source_cube, normalize(cube_interp)); #else diff --git a/drivers/gles2/shaders/cubemap_filter.glsl b/drivers/gles2/shaders/cubemap_filter.glsl index 2a1ad8d8f2..b1553c7cd5 100644 --- a/drivers/gles2/shaders/cubemap_filter.glsl +++ b/drivers/gles2/shaders/cubemap_filter.glsl @@ -167,18 +167,21 @@ void main() { vec3 H = ImportanceSampleGGX(xi, roughness, N); vec3 V = N; - vec3 L = normalize(2.0 * dot(V, H) * H - V); + vec3 L = (2.0 * dot(V, H) * H - V); float NdotL = clamp(dot(N, L), 0.0, 1.0); if (NdotL > 0.0) { #ifdef USE_SOURCE_PANORAMA - sum.rgb += texturePanorama(source_panorama, L).rgb * NdotL; + vec3 val = texturePanorama(source_panorama, L).rgb; #else - L.y = -L.y; - sum.rgb += textureCubeLod(source_cube, L, 0.0).rgb * NdotL; + vec3 val = textureCubeLod(source_cube, L, 0.0).rgb; #endif + //mix using Linear, to approximate high end back-end + val = mix(pow((val + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), val * (1.0 / 12.92), vec3(lessThan(val, vec3(0.04045)))); + + sum.rgb += val * NdotL; sum.a += NdotL; } @@ -186,5 +189,8 @@ void main() { sum /= sum.a; + vec3 a = vec3(0.055); + sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308)))); + gl_FragColor = vec4(sum.rgb, 1.0); } diff --git a/drivers/gles2/shaders/lens_distorted.glsl b/drivers/gles2/shaders/lens_distorted.glsl new file mode 100644 index 0000000000..d541db9bf9 --- /dev/null +++ b/drivers/gles2/shaders/lens_distorted.glsl @@ -0,0 +1,62 @@ +/* clang-format off */ +[vertex] + +attribute highp vec2 vertex; // attrib:0 +/* clang-format on */ + +uniform vec2 offset; +uniform vec2 scale; + +varying vec2 uv_interp; + +void main() { + + uv_interp = vertex.xy * 2.0 - 1.0; + + vec2 v = vertex.xy * scale + offset; + gl_Position = vec4(v, 0.0, 1.0); +} + +/* clang-format off */ +[fragment] + +uniform sampler2D source; //texunit:0 +/* clang-format on */ + +uniform vec2 eye_center; +uniform float k1; +uniform float k2; +uniform float upscale; +uniform float aspect_ratio; + +varying vec2 uv_interp; + +void main() { + vec2 coords = uv_interp; + vec2 offset = coords - eye_center; + + // take aspect ratio into account + offset.y /= aspect_ratio; + + // distort + vec2 offset_sq = offset * offset; + float radius_sq = offset_sq.x + offset_sq.y; + float radius_s4 = radius_sq * radius_sq; + float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); + offset *= distortion_scale; + + // reapply aspect ratio + offset.y *= aspect_ratio; + + // add our eye center back in + coords = offset + eye_center; + coords /= upscale; + + // and check our color + if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + } else { + coords = (coords + vec2(1.0)) / vec2(2.0); + gl_FragColor = texture2D(source, coords); + } +} diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index 906c089170..2a781605d1 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -5,12 +5,17 @@ #define mediump #define highp #else -precision mediump float; -precision mediump int; +precision highp float; +precision highp int; #endif #include "stdlib.glsl" +#define SHADER_IS_SRGB true + +#define M_PI 3.14159265359 + + // // attributes // @@ -23,15 +28,15 @@ attribute vec3 normal_attrib; // attrib:1 attribute vec4 tangent_attrib; // attrib:2 #endif -#ifdef ENABLE_COLOR_INTERP +#if defined(ENABLE_COLOR_INTERP) attribute vec4 color_attrib; // attrib:3 #endif -#ifdef ENABLE_UV_INTERP +#if defined(ENABLE_UV_INTERP) attribute vec2 uv_attrib; // attrib:4 #endif -#ifdef ENABLE_UV2_INTERP +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) attribute vec2 uv2_attrib; // attrib:5 #endif @@ -39,9 +44,9 @@ attribute vec2 uv2_attrib; // attrib:5 #ifdef USE_SKELETON_SOFTWARE -attribute highp vec4 bone_transform_row_0; // attrib:9 -attribute highp vec4 bone_transform_row_1; // attrib:10 -attribute highp vec4 bone_transform_row_2; // attrib:11 +attribute highp vec4 bone_transform_row_0; // attrib:13 +attribute highp vec4 bone_transform_row_1; // attrib:14 +attribute highp vec4 bone_transform_row_2; // attrib:15 #else @@ -57,12 +62,12 @@ uniform ivec2 skeleton_texture_size; #ifdef USE_INSTANCING -attribute highp vec4 instance_xform_row_0; // attrib:12 -attribute highp vec4 instance_xform_row_1; // attrib:13 -attribute highp vec4 instance_xform_row_2; // attrib:14 +attribute highp vec4 instance_xform_row_0; // attrib:8 +attribute highp vec4 instance_xform_row_1; // attrib:9 +attribute highp vec4 instance_xform_row_2; // attrib:10 -attribute highp vec4 instance_color; // attrib:15 -attribute highp vec4 instance_custom_data; // attrib:8 +attribute highp vec4 instance_color; // attrib:11 +attribute highp vec4 instance_custom_data; // attrib:12 #endif @@ -70,12 +75,12 @@ attribute highp vec4 instance_custom_data; // attrib:8 // uniforms // -uniform mat4 camera_matrix; -uniform mat4 camera_inverse_matrix; -uniform mat4 projection_matrix; -uniform mat4 projection_inverse_matrix; +uniform highp mat4 camera_matrix; +uniform highp mat4 camera_inverse_matrix; +uniform highp mat4 projection_matrix; +uniform highp mat4 projection_inverse_matrix; -uniform mat4 world_transform; +uniform highp mat4 world_transform; uniform highp float time; @@ -98,15 +103,15 @@ varying vec3 tangent_interp; varying vec3 binormal_interp; #endif -#ifdef ENABLE_COLOR_INTERP +#if defined(ENABLE_COLOR_INTERP) varying vec4 color_interp; #endif -#ifdef ENABLE_UV_INTERP +#if defined(ENABLE_UV_INTERP) varying vec2 uv_interp; #endif -#ifdef ENABLE_UV2_INTERP +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) varying vec2 uv2_interp; #endif @@ -116,6 +121,197 @@ VERTEX_SHADER_GLOBALS /* clang-format on */ +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + +varying highp float dp_clip; +uniform highp float shadow_dual_paraboloid_render_zfar; +uniform highp float shadow_dual_paraboloid_render_side; + +#endif + +#if defined(USE_SHADOW) && defined(USE_LIGHTING) + +uniform highp mat4 light_shadow_matrix; +varying highp vec4 shadow_coord; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) +uniform highp mat4 light_shadow_matrix2; +varying highp vec4 shadow_coord2; +#endif + +#if defined(LIGHT_USE_PSSM4) + +uniform highp mat4 light_shadow_matrix3; +uniform highp mat4 light_shadow_matrix4; +varying highp vec4 shadow_coord3; +varying highp vec4 shadow_coord4; + +#endif + +#endif + +#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) + +varying highp vec3 diffuse_interp; +varying highp vec3 specular_interp; + +// general for all lights +uniform highp vec4 light_color; +uniform highp float light_specular; + +// directional +uniform highp vec3 light_direction; + +// omni +uniform highp vec3 light_position; + +uniform highp float light_range; +uniform highp float light_attenuation; + +// spot +uniform highp float light_spot_attenuation; +uniform highp float light_spot_range; +uniform highp float light_spot_angle; + +void light_compute( + vec3 N, + vec3 L, + vec3 V, + vec3 light_color, + vec3 attenuation, + float roughness) { + +//this makes lights behave closer to linear, but then addition of lights looks bad +//better left disabled + +//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); +/* +#define SRGB_APPROX(m_var) {\ + float S1 = sqrt(m_var);\ + float S2 = sqrt(S1);\ + float S3 = sqrt(S2);\ + m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ + } +*/ +#define SRGB_APPROX(m_var) + + float NdotL = dot(N, L); + float cNdotL = max(NdotL, 0.0); // clamped NdotL + float NdotV = dot(N, V); + float cNdotV = max(NdotV, 0.0); + +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif + +#if defined(DIFFUSE_LAMBERT_WRAP) + // energy conserving lambert wrap shader + diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); + +#elif defined(DIFFUSE_OREN_NAYAR) + + { + // see http://mimosa-pudica.net/improved-oren-nayar.html + float LdotV = dot(L, V); + + float s = LdotV - NdotL * NdotV; + float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); + + float sigma2 = roughness * roughness; // TODO: this needs checking + vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); + float B = 0.45 * sigma2 / (sigma2 + 0.09); + + diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); + } +#else + // lambert by default for everything else + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + SRGB_APPROX(diffuse_brdf_NL) + + diffuse_interp += light_color * diffuse_brdf_NL * attenuation; + + if (roughness > 0.0) { + + // D + float specular_brdf_NL = 0.0; + +#if !defined(SPECULAR_DISABLED) + //normalized blinn always unless disabled + vec3 H = normalize(V + L); + float cNdotH = max(dot(N, H), 0.0); + float cVdotH = max(dot(V, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); +#endif + + SRGB_APPROX(specular_brdf_NL) + specular_interp += specular_brdf_NL * light_color * attenuation; + } +} + +#endif + +#ifdef USE_VERTEX_LIGHTING + +#ifdef USE_REFLECTION_PROBE1 + +uniform highp mat4 refprobe1_local_matrix; +varying mediump vec4 refprobe1_reflection_normal_blend; +uniform highp vec3 refprobe1_box_extents; + +#ifndef USE_LIGHTMAP +varying mediump vec3 refprobe1_ambient_normal; +#endif + +#endif //reflection probe1 + +#ifdef USE_REFLECTION_PROBE2 + +uniform highp mat4 refprobe2_local_matrix; +varying mediump vec4 refprobe2_reflection_normal_blend; +uniform highp vec3 refprobe2_box_extents; + +#ifndef USE_LIGHTMAP +varying mediump vec3 refprobe2_ambient_normal; +#endif + +#endif //reflection probe2 + +#endif //vertex lighting for refprobes + +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +varying vec4 fog_interp; + +uniform mediump vec4 fog_color_base; +#ifdef LIGHT_MODE_DIRECTIONAL +uniform mediump vec4 fog_sun_color_amount; +#endif + +uniform bool fog_transmit_enabled; +uniform mediump float fog_transmit_curve; + +#ifdef FOG_DEPTH_ENABLED +uniform highp float fog_depth_begin; +uniform mediump float fog_depth_curve; +uniform mediump float fog_max_distance; +#endif + +#ifdef FOG_HEIGHT_ENABLED +uniform highp float fog_height_min; +uniform highp float fog_height_max; +uniform mediump float fog_height_curve; +#endif + +#endif //fog + void main() { highp vec4 vertex = vertex_attrib; @@ -131,6 +327,7 @@ void main() { vec4(0.0, 0.0, 0.0, 1.0)); world_matrix = world_matrix * transpose(m); } + #endif vec3 normal = normal_attrib * normal_mult; @@ -142,18 +339,18 @@ void main() { vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif -#ifdef ENABLE_COLOR_INTERP +#if defined(ENABLE_COLOR_INTERP) color_interp = color_attrib; #ifdef USE_INSTANCING color_interp *= instance_color; #endif #endif -#ifdef ENABLE_UV_INTERP +#if defined(ENABLE_UV_INTERP) uv_interp = uv_attrib; #endif -#ifdef ENABLE_UV2_INTERP +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) uv2_interp = uv2_attrib; #endif @@ -162,7 +359,7 @@ void main() { normal = normalize((world_matrix * vec4(normal, 0.0)).xyz); #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent = normalize((world_matrix * vec4(tangent, 0.0)), xyz); + tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz); binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz); #endif #endif @@ -208,7 +405,8 @@ void main() { #endif - mat4 modelview = camera_matrix * world_matrix; + mat4 modelview = camera_inverse_matrix * world_matrix; + float roughness = 1.0; #define world_transform world_matrix @@ -234,11 +432,11 @@ VERTEX_SHADER_CODE #endif #if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - vertex = camera_matrix * vertex; - normal = normalize((camera_matrix * vec4(normal, 0.0)).xyz); + vertex = camera_inverse_matrix * vertex; + normal = normalize((camera_inverse_matrix * vec4(normal, 0.0)).xyz); #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent = normalize((camera_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((camera_matrix * vec4(binormal, 0.0)).xyz); + tangent = normalize((camera_inverse_matrix * vec4(tangent, 0.0)).xyz); + binormal = normalize((camera_inverse_matrix * vec4(binormal, 0.0)).xyz); #endif #endif @@ -252,13 +450,197 @@ VERTEX_SHADER_CODE #ifdef RENDER_DEPTH +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + + vertex_interp.z *= shadow_dual_paraboloid_render_side; + normal_interp.z *= shadow_dual_paraboloid_render_side; + + dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias + + //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges + + highp vec3 vtx = vertex_interp + normalize(vertex_interp) * light_bias; + highp float distance = length(vtx); + vtx = normalize(vtx); + vtx.xy /= 1.0 - vtx.z; + vtx.z = (distance / shadow_dual_paraboloid_render_zfar); + vtx.z = vtx.z * 2.0 - 1.0; + + vertex_interp = vtx; + +#else float z_ofs = light_bias; z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias; vertex_interp.z -= z_ofs; +#endif //dual parabolloid + +#endif //depth + +//vertex lighting +#if defined(USE_VERTEX_LIGHTING) && defined(USE_LIGHTING) + //vertex shaded version of lighting (more limited) + vec3 L; + vec3 light_att; + +#ifdef LIGHT_MODE_OMNI + vec3 light_vec = light_position - vertex_interp; + float light_length = length(light_vec); + + float normalized_distance = light_length / light_range; + + if (normalized_distance < 1.0) { + + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); + + vec3 attenuation = vec3(omni_attenuation); + light_att = vec3(omni_attenuation); + } else { + light_att = vec3(0.0); + } + + L = normalize(light_vec); + +#endif + +#ifdef LIGHT_MODE_SPOT + + vec3 light_rel_vec = light_position - vertex_interp; + float light_length = length(light_rel_vec); + float normalized_distance = light_length / light_range; + + if (normalized_distance < 1.0) { + + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); + vec3 spot_dir = light_direction; + + float spot_cutoff = light_spot_angle; + + float angle = dot(-normalize(light_rel_vec), spot_dir); + + if (angle > spot_cutoff) { + + float scos = max(angle, spot_cutoff); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + + spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + + light_att = vec3(spot_attenuation); + } else { + light_att = vec3(0.0); + } + } else { + light_att = vec3(0.0); + } + + L = normalize(light_rel_vec); + +#endif + +#ifdef LIGHT_MODE_DIRECTIONAL + vec3 light_vec = -light_direction; + light_att = vec3(1.0); //no base attenuation + L = normalize(light_vec); +#endif + + diffuse_interp = vec3(0.0); + specular_interp = vec3(0.0); + light_compute(normal_interp, L, -normalize(vertex_interp), light_color.rgb, light_att, roughness); + +#endif + +//shadows (for both vertex and fragment) +#if defined(USE_SHADOW) && defined(USE_LIGHTING) + + vec4 vi4 = vec4(vertex_interp, 1.0); + shadow_coord = light_shadow_matrix * vi4; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) + shadow_coord2 = light_shadow_matrix2 * vi4; +#endif + +#if defined(LIGHT_USE_PSSM4) + shadow_coord3 = light_shadow_matrix3 * vi4; + shadow_coord4 = light_shadow_matrix4 * vi4; + +#endif + +#endif //use shadow and use lighting + +#ifdef USE_VERTEX_LIGHTING + +#ifdef USE_REFLECTION_PROBE1 + { + vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); + vec3 local_pos = (refprobe1_local_matrix * vec4(vertex_interp, 1.0)).xyz; + vec3 inner_pos = abs(local_pos / refprobe1_box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + + { + vec3 local_ref_vec = (refprobe1_local_matrix * vec4(ref_normal, 0.0)).xyz; + refprobe1_reflection_normal_blend.xyz = local_ref_vec; + refprobe1_reflection_normal_blend.a = blend; + } +#ifndef USE_LIGHTMAP + + refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz; +#endif + } + +#endif //USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + { + vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); + vec3 local_pos = (refprobe2_local_matrix * vec4(vertex_interp, 1.0)).xyz; + vec3 inner_pos = abs(local_pos / refprobe2_box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + + { + vec3 local_ref_vec = (refprobe2_local_matrix * vec4(ref_normal, 0.0)).xyz; + refprobe2_reflection_normal_blend.xyz = local_ref_vec; + refprobe2_reflection_normal_blend.a = blend; + } +#ifndef USE_LIGHTMAP + refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz; #endif + } + +#endif //USE_REFLECTION_PROBE2 + +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + + float fog_amount = 0.0; + +#ifdef LIGHT_MODE_DIRECTIONAL + vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex_interp), light_direction), 0.0), 8.0)); +#else + vec3 fog_color = fog_color_base.rgb; +#endif + +#ifdef FOG_DEPTH_ENABLED + + { + + float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); + + fog_amount = pow(fog_z, fog_depth_curve); + } +#endif + +#ifdef FOG_HEIGHT_ENABLED + { + float y = (camera_matrix * vec4(vertex_interp, 1.0)).y; + fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); + } +#endif + fog_interp = vec4(fog_color, fog_amount); + +#endif //fog + +#endif //use vertex lighting gl_Position = projection_matrix * vec4(vertex_interp, 1.0); } @@ -276,41 +658,201 @@ VERTEX_SHADER_CODE #define highp #else precision mediump float; -precision mediump int; +precision highp int; #endif #include "stdlib.glsl" #define M_PI 3.14159265359 +#define SHADER_IS_SRGB true // // uniforms // -uniform mat4 camera_matrix; +uniform highp mat4 camera_matrix; /* clang-format on */ -uniform mat4 camera_inverse_matrix; -uniform mat4 projection_matrix; -uniform mat4 projection_inverse_matrix; +uniform highp mat4 camera_inverse_matrix; +uniform highp mat4 projection_matrix; +uniform highp mat4 projection_inverse_matrix; -uniform mat4 world_transform; +uniform highp mat4 world_transform; uniform highp float time; -#ifdef SCREEN_UV_USED +#if defined(SCREEN_UV_USED) uniform vec2 screen_pixel_size; #endif -uniform highp sampler2D depth_buffer; //texunit:-5 +// I think supporting this in GLES2 is difficult +// uniform highp sampler2D depth_buffer; #if defined(SCREEN_TEXTURE_USED) -uniform highp sampler2D screen_texture; //texunit:-6 +uniform highp sampler2D screen_texture; //texunit:-4 #endif -#ifdef USE_RADIANCE_MAP +#ifdef USE_REFLECTION_PROBE1 + +#ifdef USE_VERTEX_LIGHTING + +varying mediump vec4 refprobe1_reflection_normal_blend; +#ifndef USE_LIGHTMAP +varying mediump vec3 refprobe1_ambient_normal; +#endif + +#else + +uniform bool refprobe1_use_box_project; +uniform highp vec3 refprobe1_box_extents; +uniform vec3 refprobe1_box_offset; +uniform highp mat4 refprobe1_local_matrix; + +#endif //use vertex lighting + +uniform bool refprobe1_exterior; + +uniform highp samplerCube reflection_probe1; //texunit:-5 + +uniform float refprobe1_intensity; +uniform vec4 refprobe1_ambient; + +#endif //USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + +#ifdef USE_VERTEX_LIGHTING + +varying mediump vec4 refprobe2_reflection_normal_blend; +#ifndef USE_LIGHTMAP +varying mediump vec3 refprobe2_ambient_normal; +#endif + +#else + +uniform bool refprobe2_use_box_project; +uniform highp vec3 refprobe2_box_extents; +uniform vec3 refprobe2_box_offset; +uniform highp mat4 refprobe2_local_matrix; + +#endif //use vertex lighting + +uniform bool refprobe2_exterior; + +uniform highp samplerCube reflection_probe2; //texunit:-6 + +uniform float refprobe2_intensity; +uniform vec4 refprobe2_ambient; + +#endif //USE_REFLECTION_PROBE2 #define RADIANCE_MAX_LOD 6.0 +#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + +void reflection_process(samplerCube reflection_map, +#ifdef USE_VERTEX_LIGHTING + vec3 ref_normal, +#ifndef USE_LIGHTMAP + vec3 amb_normal, +#endif + float ref_blend, + +#else //no vertex lighting + vec3 normal, vec3 vertex, + mat4 local_matrix, + bool use_box_project, vec3 box_extents, vec3 box_offset, +#endif //vertex lighting + bool exterior, float intensity, vec4 ref_ambient, float roughness, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { + + vec4 reflection; + +#ifdef USE_VERTEX_LIGHTING + + reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; + + float blend = ref_blend; //crappier blend formula for vertex + blend *= blend; + blend = max(0.0, 1.0 - blend); + +#else //fragment lighting + + vec3 local_pos = (local_matrix * vec4(vertex, 1.0)).xyz; + + if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box + return; + } + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + blend = mix(length(inner_pos), blend, blend); + blend *= blend; + blend = max(0.0, 1.0 - blend); + + //reflect and make local + vec3 ref_normal = normalize(reflect(vertex, normal)); + ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz; + + if (use_box_project) { //box project + + vec3 nrdir = normalize(ref_normal); + vec3 rbmax = (box_extents - local_pos) / nrdir; + vec3 rbmin = (-box_extents - local_pos) / nrdir; + + vec3 rbminmax = mix(rbmin, rbmax, vec3(greaterThan(nrdir, vec3(0.0, 0.0, 0.0)))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + ref_normal = posonbox - box_offset.xyz; + } + + reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; +#endif + + if (exterior) { + reflection.rgb = mix(skybox, reflection.rgb, blend); + } + reflection.rgb *= intensity; + reflection.a = blend; + reflection.rgb *= blend; + + reflection_accum += reflection; + +#ifndef USE_LIGHTMAP + + vec4 ambient_out; +#ifndef USE_VERTEX_LIGHTING + + vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz; +#endif + + ambient_out.rgb = textureCubeLod(reflection_map, amb_normal, RADIANCE_MAX_LOD).rgb; + ambient_out.rgb = mix(ref_ambient.rgb, ambient_out.rgb, ref_ambient.a); + if (exterior) { + ambient_out.rgb = mix(ambient, ambient_out.rgb, blend); + } + + ambient_out.a = blend; + ambient_out.rgb *= blend; + ambient_accum += ambient_out; + +#endif +} + +#endif //use refprobe 1 or 2 + +#ifdef USE_LIGHTMAP +uniform mediump sampler2D lightmap; //texunit:-4 +uniform mediump float lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE +uniform mediump vec4[12] lightmap_captures; +uniform bool lightmap_capture_sky; + +#endif + +#ifdef USE_RADIANCE_MAP + uniform samplerCube radiance_map; // texunit:-2 uniform mat4 radiance_inverse_xform; @@ -323,49 +865,70 @@ uniform float ambient_sky_contribution; uniform vec4 ambient_color; uniform float ambient_energy; -#ifdef LIGHT_PASS +#ifdef USE_LIGHTING -#define LIGHT_TYPE_DIRECTIONAL 0 -#define LIGHT_TYPE_OMNI 1 -#define LIGHT_TYPE_SPOT 2 +#ifdef USE_VERTEX_LIGHTING -// general for all lights -uniform int light_type; +//get from vertex +varying highp vec3 diffuse_interp; +varying highp vec3 specular_interp; -uniform float light_energy; -uniform vec4 light_color; -uniform float light_specular; +uniform highp vec3 light_direction; //may be used by fog, so leave here -// directional -uniform vec3 light_direction; +#else +//done in fragment +// general for all lights +uniform highp vec4 light_color; +uniform highp float light_specular; +// directional +uniform highp vec3 light_direction; // omni -uniform vec3 light_position; +uniform highp vec3 light_position; -uniform float light_range; -uniform vec4 light_attenuation; +uniform highp float light_attenuation; // spot -uniform float light_spot_attenuation; -uniform float light_spot_range; -uniform float light_spot_angle; +uniform highp float light_spot_attenuation; +uniform highp float light_spot_range; +uniform highp float light_spot_angle; +#endif -// shadows -uniform highp sampler2D light_shadow_atlas; //texunit:-4 -uniform float light_has_shadow; +//this is needed outside above if because dual paraboloid wants it +uniform highp float light_range; + +#ifdef USE_SHADOW + +uniform highp vec2 shadow_pixel_size; + +#if defined(LIGHT_MODE_OMNI) || defined(LIGHT_MODE_SPOT) +uniform highp sampler2D light_shadow_atlas; //texunit:-3 +#endif + +#ifdef LIGHT_MODE_DIRECTIONAL +uniform highp sampler2D light_directional_shadow; // texunit:-3 +uniform highp vec4 light_split_offsets; +#endif + +varying highp vec4 shadow_coord; + +#if defined(LIGHT_USE_PSSM2) || defined(LIGHT_USE_PSSM4) +varying highp vec4 shadow_coord2; +#endif + +#if defined(LIGHT_USE_PSSM4) + +varying highp vec4 shadow_coord3; +varying highp vec4 shadow_coord4; + +#endif -uniform mat4 light_shadow_matrix; uniform vec4 light_clamp; -// directional shadow +#endif // light shadow -uniform highp sampler2D light_directional_shadow; // texunit:-4 -uniform vec4 light_split_offsets; +// directional shadow -uniform mat4 light_shadow_matrix1; -uniform mat4 light_shadow_matrix2; -uniform mat4 light_shadow_matrix3; -uniform mat4 light_shadow_matrix4; #endif // @@ -380,24 +943,25 @@ varying vec3 tangent_interp; varying vec3 binormal_interp; #endif -#ifdef ENABLE_COLOR_INTERP +#if defined(ENABLE_COLOR_INTERP) varying vec4 color_interp; #endif -#ifdef ENABLE_UV_INTERP +#if defined(ENABLE_UV_INTERP) varying vec2 uv_interp; #endif -#ifdef ENABLE_UV2_INTERP +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) varying vec2 uv2_interp; #endif varying vec3 view_interp; -vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) { - float dielectric = (0.034 * 2.0) * specular; - // energy conservation - return mix(vec3(dielectric), albedo, metallic); // TODO: reference? +vec3 F0(float metallic, float specular, vec3 albedo) { + float dielectric = 0.16 * specular * specular; + // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; + // see https://google.github.io/filament/Filament.md.html + return mix(vec3(dielectric), albedo, vec3(metallic)); } /* clang-format off */ @@ -406,7 +970,106 @@ FRAGMENT_SHADER_GLOBALS /* clang-format on */ -#ifdef LIGHT_PASS +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + +varying highp float dp_clip; + +#endif + +#ifdef USE_LIGHTING + +// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. +// We're dividing this factor off because the overall term we'll end up looks like +// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): +// +// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) +// +// We're basically regouping this as +// +// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] +// +// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. +// +// The contents of the D and G (G1) functions (GGX) are taken from +// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). +// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). + +/* +float G_GGX_2cos(float cos_theta_m, float alpha) { + // Schlick's approximation + // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) + // Eq. (19), although see Heitz (2014) the about the problems with his derivation. + // It nevertheless approximates GGX well with k = alpha/2. + float k = 0.5 * alpha; + return 0.5 / (cos_theta_m * (1.0 - k) + k); + + // float cos2 = cos_theta_m * cos_theta_m; + // float sin2 = (1.0 - cos2); + // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); +} +*/ + +// This approximates G_GGX_2cos(cos_theta_l, alpha) * G_GGX_2cos(cos_theta_v, alpha) +// See Filament docs, Specular G section. +float V_GGX(float cos_theta_l, float cos_theta_v, float alpha) { + float v = cos_theta_l * (cos_theta_v * (1.0 - alpha) + alpha); + float l = cos_theta_v * (cos_theta_l * (1.0 - alpha) + alpha); + return 0.5 / (v + l); +} + +float D_GGX(float cos_theta_m, float alpha) { + float alpha2 = alpha * alpha; + float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m; + return alpha2 / (M_PI * d * d); +} + +/* +float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float s_x = alpha_x * cos_phi; + float s_y = alpha_y * sin_phi; + return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); +} +*/ + +// This approximates G_GGX_anisotropic_2cos(cos_theta_l, ...) * G_GGX_anisotropic_2cos(cos_theta_v, ...) +// See Filament docs, Anisotropic specular BRDF section. +float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { + float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); + float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); + return 0.5 / (Lambda_V + Lambda_L); +} + +float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) { + float alpha2 = alpha_x * alpha_y; + highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH); + highp float v2 = dot(v, v); + float w2 = alpha2 / v2; + float D = alpha2 * w2 * w2 * (1.0 / M_PI); + return D; + + /* float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0 - cos2); + float r_x = cos_phi / alpha_x; + float r_y = sin_phi / alpha_y; + float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); + return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); */ +} + +float SchlickFresnel(float u) { + float m = 1.0 - u; + float m2 = m * m; + return m2 * m2 * m; // pow(m,5) +} + +float GTR1(float NdotH, float a) { + if (a >= 1.0) return 1.0 / M_PI; + float a2 = a * a; + float t = 1.0 + (a2 - 1.0) * NdotH * NdotH; + return (a2 - 1.0) / (M_PI * log(a2) * t); +} + void light_compute( vec3 N, vec3 L, @@ -420,6 +1083,7 @@ void light_compute( float specular_blob_intensity, float roughness, float metallic, + float specular, float rim, float rim_tint, float clearcoat, @@ -428,52 +1092,305 @@ void light_compute( inout vec3 diffuse_light, inout vec3 specular_light) { +//this makes lights behave closer to linear, but then addition of lights looks bad +//better left disabled + +//#define SRGB_APPROX(m_var) m_var = pow(m_var,0.4545454545); +/* +#define SRGB_APPROX(m_var) {\ + float S1 = sqrt(m_var);\ + float S2 = sqrt(S1);\ + float S3 = sqrt(S2);\ + m_var = 0.662002687 * S1 + 0.684122060 * S2 - 0.323583601 * S3 - 0.0225411470 * m_var;\ + } +*/ +#define SRGB_APPROX(m_var) + +#if defined(USE_LIGHT_SHADER_CODE) + // light is written by the light shader + + vec3 normal = N; + vec3 albedo = diffuse_color; + vec3 light = L; + vec3 view = V; + + /* clang-format off */ + +LIGHT_SHADER_CODE + + /* clang-format on */ + +#else float NdotL = dot(N, L); - float cNdotL = max(NdotL, 0.0); + float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); - { - // calculate diffuse reflection - - // TODO hardcode Oren Nayar for now - float diffuse_brdf_NL; + if (metallic < 1.0) { +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif +#if defined(DIFFUSE_LAMBERT_WRAP) + // energy conserving lambert wrap shader diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness))); - // diffuse_brdf_NL = cNdotL * (1.0 / M_PI); + +#elif defined(DIFFUSE_OREN_NAYAR) + + { + // see http://mimosa-pudica.net/improved-oren-nayar.html + float LdotV = dot(L, V); + + float s = LdotV - NdotL * NdotV; + float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); + + float sigma2 = roughness * roughness; // TODO: this needs checking + vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13)); + float B = 0.45 * sigma2 / (sigma2 + 0.09); + + diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); + } + +#elif defined(DIFFUSE_TOON) + + diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL); + +#elif defined(DIFFUSE_BURLEY) + + { + + vec3 H = normalize(V + L); + float cLdotH = max(0.0, dot(L, H)); + + float FD90 = 0.5 + 2.0 * cLdotH * cLdotH * roughness; + float FdV = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotV); + float FdL = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotL); + diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; + /* + float energyBias = mix(roughness, 0.0, 0.5); + float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); + float fd90 = energyBias + 2.0 * VoH * VoH * roughness; + float f0 = 1.0; + float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); + float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); + + diffuse_brdf_NL = lightScatter * viewScatter * energyFactor; + */ + } +#else + // lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + + SRGB_APPROX(diffuse_brdf_NL) diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; + +#if defined(TRANSMISSION_USED) + diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation; +#endif + +#if defined(LIGHT_USE_RIM) + float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0)); + diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color; +#endif } - { - // calculate specular reflection + if (roughness > 0.0) { + +#if defined(SPECULAR_SCHLICK_GGX) + vec3 specular_brdf_NL = vec3(0.0); +#else + float specular_brdf_NL = 0.0; +#endif + +#if defined(SPECULAR_BLINN) + + //normalized blinn + vec3 H = normalize(V + L); + float cNdotH = max(dot(N, H), 0.0); + float cVdotH = max(dot(V, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + +#elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L, N)); - float cRdotV = max(dot(R, V), 0.0); - float blob_intensity = pow(cRdotV, (1.0 - roughness) * 256.0); - specular_light += light_color * attenuation * blob_intensity * specular_blob_intensity; + float cRdotV = max(0.0, dot(R, V)); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float phong = pow(cRdotV, shininess); + phong *= (shininess + 8.0) / (8.0 * 3.141592654); + specular_brdf_NL = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + +#elif defined(SPECULAR_TOON) + + vec3 R = normalize(-reflect(L, N)); + float RdotV = dot(R, V); + float mid = 1.0 - roughness; + mid *= mid; + specular_brdf_NL = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid; + +#elif defined(SPECULAR_DISABLED) + // none.. +#elif defined(SPECULAR_SCHLICK_GGX) + // shlick+ggx as default + + vec3 H = normalize(V + L); + + float cNdotH = max(dot(N, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + +#if defined(LIGHT_USE_ANISOTROPY) + float alpha = roughness * roughness; + float aspect = sqrt(1.0 - anisotropy * 0.9); + float ax = alpha / aspect; + float ay = alpha * aspect; + float XdotH = dot(T, H); + float YdotH = dot(B, H); + float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH, cNdotH); + //float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL)) + +#else + float alpha = roughness * roughness; + float D = D_GGX(cNdotH, alpha); + //float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); + float G = V_GGX(cNdotL, cNdotV, alpha); +#endif + // F + vec3 f0 = F0(metallic, specular, diffuse_color); + float cLdotH5 = SchlickFresnel(cLdotH); + vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); + + specular_brdf_NL = cNdotL * D * F * G; + +#endif + + SRGB_APPROX(specular_brdf_NL) + specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; + +#if defined(LIGHT_USE_CLEARCOAT) + if (clearcoat_gloss > 0.0) { +#if !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) + vec3 H = normalize(V + L); +#endif +#if !defined(SPECULAR_SCHLICK_GGX) + float cNdotH = max(dot(N, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + float cLdotH5 = SchlickFresnel(cLdotH); +#endif + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + //float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + float Gr = V_GGX(cNdotL, cNdotV, 0.25); + + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + + specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; + } +#endif } + +#endif //defined(USE_LIGHT_SHADER_CODE) } +#endif // shadows -float sample_shadow( - highp sampler2D shadow, - vec2 shadow_pixel_size, - vec2 pos, - float depth, - vec4 clamp_rect) { - // vec4 depth_value = texture2D(shadow, pos); - - // return depth_value.z; - return texture2DProj(shadow, vec4(pos, depth, 1.0)).r; - // return (depth_value.x + depth_value.y + depth_value.z + depth_value.w) / 4.0; +#ifdef USE_SHADOW + +#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, texture2D(p_shadow, p_pos).r) +#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, texture2DProj(p_shadow, p_pos).r) + +float sample_shadow(highp sampler2D shadow, highp vec4 spos) { + +#ifdef SHADOW_MODE_PCF_13 + + spos.xyz /= spos.w; + vec2 pos = spos.xy; + float depth = spos.z; + + float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth); + return avg * (1.0 / 13.0); +#endif + +#ifdef SHADOW_MODE_PCF_5 + + spos.xyz /= spos.w; + vec2 pos = spos.xy; + float depth = spos.z; + + float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, shadow_pixel_size.y), depth); + avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(0.0, -shadow_pixel_size.y), depth); + return avg * (1.0 / 5.0); + +#endif + +#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) + + return SAMPLE_SHADOW_TEXEL_PROJ(shadow, spos); +#endif } #endif +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#if defined(USE_VERTEX_LIGHTING) + +varying vec4 fog_interp; + +#else +uniform mediump vec4 fog_color_base; +#ifdef LIGHT_MODE_DIRECTIONAL +uniform mediump vec4 fog_sun_color_amount; +#endif + +uniform bool fog_transmit_enabled; +uniform mediump float fog_transmit_curve; + +#ifdef FOG_DEPTH_ENABLED +uniform highp float fog_depth_begin; +uniform mediump float fog_depth_curve; +uniform mediump float fog_max_distance; +#endif + +#ifdef FOG_HEIGHT_ENABLED +uniform highp float fog_height_min; +uniform highp float fog_height_max; +uniform mediump float fog_height_curve; +#endif + +#endif //vertex lit +#endif //fog + void main() { +#ifdef RENDER_DEPTH_DUAL_PARABOLOID + + if (dp_clip > 0.0) + discard; +#endif highp vec3 vertex = vertex_interp; vec3 albedo = vec3(1.0); vec3 transmission = vec3(0.0); @@ -487,10 +1404,16 @@ void main() { float clearcoat_gloss = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); + float sss_strength = 0.0; //unused float alpha = 1.0; float side = 1.0; + float specular_blob_intensity = 1.0; +#if defined(SPECULAR_TOON) + specular_blob_intensity *= specular * 2.0; +#endif + #if defined(ENABLE_AO) float ao = 1.0; float ao_light_affect = 0.0; @@ -510,11 +1433,11 @@ void main() { #endif float normaldepth = 1.0; -#ifdef ALPHA_SCISSOR_USED +#if defined(ALPHA_SCISSOR_USED) float alpha_scissor = 0.5; #endif -#ifdef SCREEN_UV_USED +#if defined(SCREEN_UV_USED) vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; #endif @@ -530,8 +1453,8 @@ FRAGMENT_SHADER_CODE normalmap.xy = normalmap.xy * 2.0 - 1.0; normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); - // normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; - normal = normalmap; + normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; + //normal = normalmap; #endif normal = normalize(normal); @@ -540,300 +1463,513 @@ FRAGMENT_SHADER_CODE vec3 specular_light = vec3(0.0, 0.0, 0.0); vec3 diffuse_light = vec3(0.0, 0.0, 0.0); - vec3 ambient_light = vec3(0.0, 0.0, 0.0); - vec3 env_reflection_light = vec3(0.0, 0.0, 0.0); - vec3 eye_position = -normalize(vertex_interp); -#ifdef ALPHA_SCISSOR_USED +#if defined(ALPHA_SCISSOR_USED) if (alpha < alpha_scissor) { discard; } #endif +#ifdef BASE_PASS + //none +#ifdef USE_RADIANCE_MAP + + vec3 ref_vec = reflect(-eye_position, N); + ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); + + ref_vec.z *= -1.0; + + specular_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; + + { + vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz); + vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).xyz * bg_energy; + + ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); + } + +#else + + ambient_light = ambient_color.rgb; + +#endif + + ambient_light *= ambient_energy; + +#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + + vec4 ambient_accum = vec4(0.0); + vec4 reflection_accum = vec4(0.0); + +#ifdef USE_REFLECTION_PROBE1 + + reflection_process(reflection_probe1, +#ifdef USE_VERTEX_LIGHTING + refprobe1_reflection_normal_blend.rgb, +#ifndef USE_LIGHTMAP + refprobe1_ambient_normal, +#endif + refprobe1_reflection_normal_blend.a, +#else + normal_interp, vertex_interp, refprobe1_local_matrix, + refprobe1_use_box_project, refprobe1_box_extents, refprobe1_box_offset, +#endif + refprobe1_exterior, refprobe1_intensity, refprobe1_ambient, roughness, + ambient_light, specular_light, reflection_accum, ambient_accum); + +#endif // USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + + reflection_process(reflection_probe2, +#ifdef USE_VERTEX_LIGHTING + refprobe2_reflection_normal_blend.rgb, +#ifndef USE_LIGHTMAP + refprobe2_ambient_normal, +#endif + refprobe2_reflection_normal_blend.a, +#else + normal_interp, vertex_interp, refprobe2_local_matrix, + refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset, +#endif + refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness, + ambient_light, specular_light, reflection_accum, ambient_accum); + +#endif // USE_REFLECTION_PROBE2 + + if (reflection_accum.a > 0.0) { + specular_light = reflection_accum.rgb / reflection_accum.a; + } + +#ifndef USE_LIGHTMAP + if (ambient_accum.a > 0.0) { + ambient_light = ambient_accum.rgb / ambient_accum.a; + } +#endif + +#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + +#ifdef USE_LIGHTMAP + //ambient light will come entirely from lightmap is lightmap is used + ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE + { + vec3 cone_dirs[12] = vec3[]( + vec3(0, 0, 1), + vec3(0.866025, 0, 0.5), + vec3(0.267617, 0.823639, 0.5), + vec3(-0.700629, 0.509037, 0.5), + vec3(-0.700629, -0.509037, 0.5), + vec3(0.267617, -0.823639, 0.5), + vec3(0, 0, -1), + vec3(0.866025, 0, -0.5), + vec3(0.267617, 0.823639, -0.5), + vec3(-0.700629, 0.509037, -0.5), + vec3(-0.700629, -0.509037, -0.5), + vec3(0.267617, -0.823639, -0.5)); + + vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz; + vec4 captured = vec4(0.0); + float sum = 0.0; + for (int i = 0; i < 12; i++) { + float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect + captured += lightmap_captures[i] * amount; + sum += amount; + } + + captured /= sum; + + if (lightmap_capture_sky) { + ambient_light = mix(ambient_light, captured.rgb, captured.a); + } else { + ambient_light = captured.rgb; + } + } +#endif + +#endif //BASE PASS + // // Lighting // -#ifdef LIGHT_PASS +#ifdef USE_LIGHTING + +#ifndef USE_VERTEX_LIGHTING + vec3 L; +#endif + vec3 light_att = vec3(1.0); - if (light_type == LIGHT_TYPE_OMNI) { - vec3 light_vec = light_position - vertex; - float light_length = length(light_vec); +#ifdef LIGHT_MODE_OMNI - float normalized_distance = light_length / light_range; +#ifndef USE_VERTEX_LIGHTING + vec3 light_vec = light_position - vertex; + float light_length = length(light_vec); - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); + float normalized_distance = light_length / light_range; + if (normalized_distance < 1.0) { - vec3 attenuation = vec3(omni_attenuation); + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - if (light_has_shadow > 0.5) { - highp vec3 splane = (light_shadow_matrix * vec4(vertex, 1.0)).xyz; - float shadow_len = length(splane); + light_att = vec3(omni_attenuation); + } else { + light_att = vec3(0.0); + } + L = normalize(light_vec); + +#endif + +#ifdef USE_SHADOW + { + highp vec4 splane = shadow_coord; + float shadow_len = length(splane.xyz); - splane = normalize(splane); + splane.xyz = normalize(splane.xyz); + + vec4 clamp_rect = light_clamp; + + if (splane.z >= 0.0) { + splane.z += 1.0; + + clamp_rect.y += clamp_rect.w; + } else { + splane.z = 1.0 - splane.z; + } - vec4 clamp_rect = light_clamp; + splane.xy /= splane.z; + splane.xy = splane.xy * 0.5 + 0.5; + splane.z = shadow_len / light_range; - if (splane.z >= 0.0) { - splane.z += 1.0; + splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; - clamp_rect.y += clamp_rect.w; + float shadow = sample_shadow(light_shadow_atlas, splane); + + light_att *= shadow; + } +#endif + +#endif //type omni + +#ifdef LIGHT_MODE_DIRECTIONAL + +#ifndef USE_VERTEX_LIGHTING + vec3 light_vec = -light_direction; + L = normalize(light_vec); +#endif + float depth_z = -vertex.z; + +#ifdef USE_SHADOW + +#ifdef USE_VERTEX_LIGHTING + //compute shadows in a mobile friendly way + +#ifdef LIGHT_USE_PSSM4 + //take advantage of prefetch + float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); + float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); + float shadow3 = sample_shadow(light_directional_shadow, shadow_coord3); + float shadow4 = sample_shadow(light_directional_shadow, shadow_coord4); + + if (depth_z < light_split_offsets.w) { + float pssm_fade = 0.0; + float shadow_att = 1.0; +#ifdef LIGHT_USE_PSSM_BLEND + float shadow_att2 = 1.0; + float pssm_blend = 0.0; + bool use_blend = true; +#endif + if (depth_z < light_split_offsets.y) { + if (depth_z < light_split_offsets.x) { + shadow_att = shadow1; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow2; + + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); +#endif } else { - splane.z = 1.0 - splane.z; - } + shadow_att = shadow2; - splane.xy /= splane.z; - splane.xy = splane.xy * 0.5 + 0.5; - splane.z = shadow_len / light_range; +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow3; - splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#endif + } + } else { + if (depth_z < light_split_offsets.z) { - float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), splane.xy, splane.z, clamp_rect); + shadow_att = shadow3; + +#if defined(LIGHT_USE_PSSM_BLEND) + shadow_att2 = shadow4; + pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); +#endif - if (shadow > splane.z) { } else { - attenuation = vec3(0.0); + + shadow_att = shadow4; + pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); + +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend = false; +#endif } } +#if defined(LIGHT_USE_PSSM_BLEND) + if (use_blend) { + shadow_att = mix(shadow_att, shadow_att2, pssm_blend); + } +#endif + light_att *= shadow_att; + } + +#endif //LIGHT_USE_PSSM4 + +#ifdef LIGHT_USE_PSSM2 + + //take advantage of prefetch + float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); + float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); + + if (depth_z < light_split_offsets.y) { + float shadow_att = 1.0; + float pssm_fade = 0.0; + +#ifdef LIGHT_USE_PSSM_BLEND + float shadow_att2 = 1.0; + float pssm_blend = 0.0; + bool use_blend = true; +#endif + if (depth_z < light_split_offsets.x) { + float pssm_fade = 0.0; + shadow_att = shadow1; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow2; + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); +#endif + } else { + + shadow_att = shadow2; + pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#ifdef LIGHT_USE_PSSM_BLEND + use_blend = false; +#endif + } +#ifdef LIGHT_USE_PSSM_BLEND + if (use_blend) { + shadow_att = mix(shadow_att, shadow_att2, pssm_blend); + } +#endif + light_att *= shadow_att; + } + +#endif //LIGHT_USE_PSSM2 + +#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) + + light_att *= sample_shadow(light_directional_shadow, shadow_coord); +#endif //orthogonal - light_compute( - normal, - normalize(light_vec), - eye_position, - binormal, - tangent, - light_color.xyz * light_energy, - attenuation, - albedo, - transmission, - specular * light_specular, - roughness, - metallic, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light); - - } else if (light_type == LIGHT_TYPE_DIRECTIONAL) { - - vec3 light_vec = -light_direction; - vec3 attenuation = vec3(1.0, 1.0, 1.0); - - float depth_z = -vertex.z; - - if (light_has_shadow > 0.5) { +#else //fragment version of pssm + { #ifdef LIGHT_USE_PSSM4 - if (depth_z < light_split_offsets.w) { + if (depth_z < light_split_offsets.w) { #elif defined(LIGHT_USE_PSSM2) - if (depth_z < light_split_offsets.y) { + if (depth_z < light_split_offsets.y) { #else - if (depth_z < light_split_offsets.x) { -#endif + if (depth_z < light_split_offsets.x) { +#endif //pssm2 - vec3 pssm_coord; - float pssm_fade = 0.0; + highp vec4 pssm_coord; + float pssm_fade = 0.0; #ifdef LIGHT_USE_PSSM_BLEND - float pssm_blend; - vec3 pssm_coord2; - bool use_blend = true; + float pssm_blend; + highp vec4 pssm_coord2; + bool use_blend = true; #endif #ifdef LIGHT_USE_PSSM4 - if (depth_z < light_split_offsets.y) { - if (depth_z < light_split_offsets.x) { - highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; + + if (depth_z < light_split_offsets.y) { + if (depth_z < light_split_offsets.x) { + pssm_coord = shadow_coord; #ifdef LIGHT_USE_PSSM_BLEND - splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord2; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif - } else { - highp vec4 splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; + } else { + pssm_coord = shadow_coord2; #ifdef LIGHT_USE_PSSM_BLEND - splane = (light_shadow_matrix3 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord3; - pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); + pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); #endif - } - } else { - if (depth_z < light_split_offsets.z) { + } + } else { + if (depth_z < light_split_offsets.z) { - highp vec4 splane = (light_shadow_matrix3 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord3; #if defined(LIGHT_USE_PSSM_BLEND) - splane = (light_shadow_matrix4 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); + pssm_coord2 = shadow_coord4; + pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); #endif - } else { + } else { - highp vec4 splane = (light_shadow_matrix4 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); + pssm_coord = shadow_coord4; + pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); #if defined(LIGHT_USE_PSSM_BLEND) - use_blend = false; + use_blend = false; #endif - } } + } #endif // LIGHT_USE_PSSM4 #ifdef LIGHT_USE_PSSM2 - if (depth_z < light_split_offsets.x) { + if (depth_z < light_split_offsets.x) { - highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord; #ifdef LIGHT_USE_PSSM_BLEND - splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord2 = splane.xyz / splane.w; - pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); + pssm_coord2 = shadow_coord2; + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif - } else { - highp vec4 splane = (light_shadow_matrix2 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); + } else { + + pssm_coord = shadow_coord2; + pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); #ifdef LIGHT_USE_PSSM_BLEND - use_blend = false; + use_blend = false; #endif - } + } #endif // LIGHT_USE_PSSM2 #if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) - { - highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0)); - pssm_coord = splane.xyz / splane.w; - } + { + pssm_coord = shadow_coord; + } #endif - float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord.xy, pssm_coord.z, light_clamp); + float shadow = sample_shadow(light_directional_shadow, pssm_coord); #ifdef LIGHT_USE_PSSM_BLEND - if (use_blend) { - shadow = mix(shadow, sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord2.xy, pssm_coord2.z, light_clamp), pssm_blend); - } + if (use_blend) { + shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2), pssm_blend); + } #endif - attenuation *= shadow; - } + light_att *= shadow; } + } +#endif //use vertex lighting - light_compute(normal, - normalize(light_vec), - eye_position, - binormal, - tangent, - light_color.xyz * light_energy, - attenuation, - albedo, - transmission, - specular * light_specular, - roughness, - metallic, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light); - } else if (light_type == LIGHT_TYPE_SPOT) { - - vec3 light_att = vec3(1.0); - - if (light_has_shadow > 0.5) { - highp vec4 splane = (light_shadow_matrix * vec4(vertex, 1.0)); - splane.xyz /= splane.w; - - float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), splane.xy, splane.z, light_clamp); - - if (shadow > splane.z) { - } else { - light_att = vec3(0.0); - } - } +#endif //use shadow - vec3 light_rel_vec = light_position - vertex; - float light_length = length(light_rel_vec); - float normalized_distance = light_length / light_range; +#endif - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); - vec3 spot_dir = light_direction; +#ifdef LIGHT_MODE_SPOT - float spot_cutoff = light_spot_angle; + light_att = vec3(1.0); - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); - - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - - light_att *= vec3(spot_attenuation); - - light_compute( - normal, - normalize(light_rel_vec), - eye_position, - binormal, - tangent, - light_color.xyz * light_energy, - light_att, - albedo, - transmission, - specular * light_specular, - roughness, - metallic, - rim, - rim_tint, - clearcoat, - clearcoat_gloss, - anisotropy, - diffuse_light, - specular_light); - } +#ifndef USE_VERTEX_LIGHTING - gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); -#else + vec3 light_rel_vec = light_position - vertex; + float light_length = length(light_rel_vec); + float normalized_distance = light_length / light_range; -#ifdef RENDER_DEPTH + if (normalized_distance < 1.0) { + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); + vec3 spot_dir = light_direction; -#else + float spot_cutoff = light_spot_angle; + float angle = dot(-normalize(light_rel_vec), spot_dir); -#ifdef USE_RADIANCE_MAP + if (angle > spot_cutoff) { + float scos = max(angle, spot_cutoff); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - vec3 ref_vec = reflect(-eye_position, N); - ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz); + light_att = vec3(spot_attenuation); + } else { + light_att = vec3(0.0); + } + } else { + light_att = vec3(0.0); + } - ref_vec.z *= -1.0; + L = normalize(light_rel_vec); - env_reflection_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy; +#endif +#ifdef USE_SHADOW { - vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz); - vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).xyz * bg_energy; + highp vec4 splane = shadow_coord; + splane.xyz /= splane.w; - ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution); + float shadow = sample_shadow(light_shadow_atlas, splane); + light_att *= shadow; } +#endif - ambient_light *= ambient_energy; +#endif // LIGHT_MODE_SPOT + +#ifdef USE_VERTEX_LIGHTING + //vertex lighting + + specular_light += specular_interp * specular_blob_intensity * light_att; + diffuse_light += diffuse_interp * albedo * light_att; - specular_light += env_reflection_light; +#else + //fragment lighting + light_compute( + normal, + L, + eye_position, + binormal, + tangent, + light_color.xyz, + light_att, + albedo, + transmission, + specular_blob_intensity * light_specular, + roughness, + metallic, + specular, + rim, + rim_tint, + clearcoat, + clearcoat_gloss, + anisotropy, + diffuse_light, + specular_light); + +#endif //vertex lighting + +#endif //USE_LIGHTING + //compute and merge + +#ifndef RENDER_DEPTH + +#ifdef SHADELESS + + gl_FragColor = vec4(albedo, alpha); +#else ambient_light *= albedo; @@ -849,26 +1985,79 @@ FRAGMENT_SHADER_CODE // environment BRDF approximation - // TODO shadeless { + +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + //TODO: this curve is not really designed for gammaspace, should be adjusted const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); vec4 r = roughness * c0 + c1; float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; - vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo); - specular_light *= AB.x * specular_color + AB.y; + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; +#endif } gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); + + //add emission if in base pass +#ifdef BASE_PASS + gl_FragColor.rgb += emission; +#endif // gl_FragColor = vec4(normal, 1.0); +#endif //unshaded + +//apply fog +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#if defined(USE_VERTEX_LIGHTING) + + gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_interp.rgb, fog_interp.a); +#else //pixel based fog + float fog_amount = 0.0; + +#ifdef LIGHT_MODE_DIRECTIONAL + + vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(eye_position, light_direction), 0.0), 8.0)); #else - gl_FragColor = vec4(albedo, alpha); + vec3 fog_color = fog_color_base.rgb; +#endif + +#ifdef FOG_DEPTH_ENABLED + + { + + float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); + + fog_amount = pow(fog_z, fog_depth_curve); + + if (fog_transmit_enabled) { + vec3 total_light = gl_FragColor.rgb; + float transmit = pow(fog_z, fog_transmit_curve); + fog_color = mix(max(total_light, fog_color), fog_color, transmit); + } + } #endif -#endif // RENDER_DEPTH -#endif // lighting +#ifdef FOG_HEIGHT_ENABLED + { + float y = (camera_matrix * vec4(vertex, 1.0)).y; + fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); + } +#endif + + gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_color, fog_amount); + +#endif //use vertex lit + +#endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#endif // not RENDER_DEPTH } diff --git a/drivers/gles2/shaders/stdlib.glsl b/drivers/gles2/shaders/stdlib.glsl index 6bc81a22d8..3674d70c9f 100644 --- a/drivers/gles2/shaders/stdlib.glsl +++ b/drivers/gles2/shaders/stdlib.glsl @@ -35,3 +35,13 @@ highp vec4 texel2DFetch(highp sampler2D tex, ivec2 size, ivec2 coord) { return texture2DLod(tex, vec2(x_coord, y_coord), 0.0); } + +#ifndef USE_GLES_OVER_GL +highp mat4 transpose(highp mat4 src) { + return mat4( + vec4(src[0].x, src[1].x, src[2].x, src[3].x), + vec4(src[0].y, src[1].y, src[2].y, src[3].y), + vec4(src[0].z, src[1].z, src[2].z, src[3].z), + vec4(src[0].w, src[1].w, src[2].w, src[3].w)); +} +#endif diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index fc41f17164..f0932c2f80 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -29,10 +29,12 @@ /*************************************************************************/ #include "rasterizer_canvas_gles3.h" -#include "os/os.h" -#include "project_settings.h" + +#include "core/os/os.h" +#include "core/project_settings.h" #include "rasterizer_scene_gles3.h" #include "servers/visual/visual_server_raster.h" + #ifndef GLES_OVER_GL #define glClearDepth glClearDepthf #endif @@ -1221,8 +1223,6 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons bool rebind_shader = true; - Size2 rt_size = Size2(storage->frame.current_rt->width, storage->frame.current_rt->height); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); @@ -1418,7 +1418,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons if (blend_mode == RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) { blend_mode = RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX; } - bool unshaded = shader_cache && (shader_cache->canvas_item.light_mode == RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_UNSHADED || blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX); + bool unshaded = shader_cache && (shader_cache->canvas_item.light_mode == RasterizerStorageGLES3::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_PMALPHA)); bool reclip = false; if (last_blend_mode != blend_mode) { @@ -1869,6 +1869,39 @@ void RasterizerCanvasGLES3::draw_generic_textured_rect(const Rect2 &p_rect, cons glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } +void RasterizerCanvasGLES3::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + Vector2 half_size; + if (storage->frame.current_rt) { + half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height); + } else { + half_size = OS::get_singleton()->get_window_size(); + } + half_size *= 0.5; + Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y); + Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y); + + float aspect_ratio = p_rect.size.x / p_rect.size.y; + + // setup our lens shader + state.lens_shader.bind(); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::OFFSET, offset); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::SCALE, scale); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::K1, p_k1); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::K2, p_k2); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::EYE_CENTER, p_eye_center); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::UPSCALE, p_oversample); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_item_ubo); + glBindVertexArray(data.canvas_quad_array); + + // and draw + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindVertexArray(0); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0); +} + void RasterizerCanvasGLES3::draw_window_margins(int *black_margin, RID *black_image) { Vector2 window_size = OS::get_singleton()->get_window_size(); @@ -1994,6 +2027,7 @@ void RasterizerCanvasGLES3::initialize() { { uint32_t poly_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); poly_size *= 1024; //kb poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); glGenBuffers(1, &data.polygon_buffer); @@ -2041,6 +2075,7 @@ void RasterizerCanvasGLES3::initialize() { glGenVertexArrays(1, &data.polygon_buffer_pointer_array); uint32_t index_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); index_size *= 1024; //kb glGenBuffers(1, &data.polygon_index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); @@ -2058,6 +2093,7 @@ void RasterizerCanvasGLES3::initialize() { state.canvas_shader.init(); state.canvas_shader.set_base_material_tex_index(2); state.canvas_shadow_shader.init(); + state.lens_shader.init(); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index c7f2e54efb..3f306003b4 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -33,7 +33,9 @@ #include "rasterizer_storage_gles3.h" #include "servers/visual/rasterizer.h" + #include "shaders/canvas_shadow.glsl.gen.h" +#include "shaders/lens_distorted.glsl.gen.h" class RasterizerSceneGLES3; @@ -71,6 +73,7 @@ public: bool canvas_texscreen_used; CanvasShaderGLES3 canvas_shader; CanvasShadowShaderGLES3 canvas_shadow_shader; + LensDistortedShaderGLES3 lens_shader; bool using_texture_rect; bool using_ninepatch; @@ -140,6 +143,7 @@ public: virtual void reset_canvas(); void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); + void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); void initialize(); void finalize(); diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index e4824695d5..2f6a556773 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -30,11 +30,9 @@ #include "rasterizer_gles3.h" -#include "gl_context/context_gl.h" -#include "os/os.h" -#include "project_settings.h" - -#include <string.h> +#include "core/os/os.h" +#include "core/project_settings.h" +#include "drivers/gl_context/context_gl.h" RasterizerStorage *RasterizerGLES3::get_storage() { @@ -75,6 +73,12 @@ RasterizerScene *RasterizerGLES3::get_scene() { #define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 #define _EXT_DEBUG_OUTPUT 0x92E0 +#if defined(MINGW_ENABLED) || defined(_MSC_VER) +#define strcpy strcpy_s +#endif + +#ifdef GLAD_ENABLED +// Restricting to GLAD as only used in initialize() with GLAD_GL_ARB_debug_output #if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) #define GLAPIENTRY APIENTRY #else @@ -125,6 +129,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL ERR_PRINTS(output); } +#endif // GLAD_ENABLED typedef void (*DEBUGPROCARB)(GLenum source, GLenum type, @@ -361,6 +366,26 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re #endif } +void RasterizerGLES3::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + ERR_FAIL_COND(storage->frame.current_rt); + + RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + glDisable(GL_BLEND); + + // render to our framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); + + // output our texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rt->color); + + canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample); + + glBindTexture(GL_TEXTURE_2D, 0); +} + void RasterizerGLES3::end_frame(bool p_swap_buffers) { if (OS::get_singleton()->is_layered_allowed()) { @@ -411,6 +436,7 @@ void RasterizerGLES3::register_config() { GLOBAL_DEF("rendering/quality/filters/anisotropic_filter_level", 4); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/anisotropic_filter_level", PropertyInfo(Variant::INT, "rendering/quality/filters/anisotropic_filter_level", PROPERTY_HINT_RANGE, "1,16,1")); GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::REAL, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); } RasterizerGLES3::RasterizerGLES3() { diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 0a264caf8f..477e0dfd48 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -59,6 +59,7 @@ public: virtual void restore_render_target(); virtual void clear_render_target(const Color &p_color); virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0); + virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); virtual void end_frame(bool p_swap_buffers); virtual void finalize(); @@ -66,6 +67,8 @@ public: static void make_current(); static void register_config(); + virtual bool is_low_end() const { return false; } + RasterizerGLES3(); ~RasterizerGLES3(); }; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 88f14890ef..792e9eb238 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -29,9 +29,10 @@ /*************************************************************************/ #include "rasterizer_scene_gles3.h" -#include "math_funcs.h" -#include "os/os.h" -#include "project_settings.h" + +#include "core/math/math_funcs.h" +#include "core/os/os.h" +#include "core/project_settings.h" #include "rasterizer_canvas_gles3.h" #include "servers/visual/visual_server_raster.h" @@ -50,26 +51,6 @@ static const GLenum _cube_side_enum[6] = { }; -static _FORCE_INLINE_ void store_transform2d(const Transform2D &p_mtx, float *p_array) { - - p_array[0] = p_mtx.elements[0][0]; - p_array[1] = p_mtx.elements[0][1]; - p_array[2] = 0; - p_array[3] = 0; - p_array[4] = p_mtx.elements[1][0]; - p_array[5] = p_mtx.elements[1][1]; - p_array[6] = 0; - p_array[7] = 0; - p_array[8] = 0; - p_array[9] = 0; - p_array[10] = 1; - p_array[11] = 0; - p_array[12] = p_mtx.elements[2][0]; - p_array[13] = p_mtx.elements[2][1]; - p_array[14] = 0; - p_array[15] = 1; -} - static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) { p_array[0] = p_mtx.basis.elements[0][0]; p_array[1] = p_mtx.basis.elements[1][0]; @@ -672,7 +653,7 @@ bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance int best_free = -1; int best_used = -1; - uint64_t best_used_frame; + uint64_t best_used_frame = 0; for (int i = 0; i < reflection_atlas->reflections.size(); i++) { if (reflection_atlas->reflections[i].owner == RID()) { @@ -1201,7 +1182,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m glActiveTexture(GL_TEXTURE0 + i); - GLenum target; + GLenum target = GL_TEXTURE_2D; GLuint tex = 0; RasterizerStorageGLES3::Texture *t = storage->texture_owner.getptr(textures[i]); @@ -1265,14 +1246,11 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m case ShaderLanguage::TYPE_SAMPLER3D: { target = GL_TEXTURE_3D; + tex = storage->resources.white_tex_3d; - switch (texture_hints[i]) { - - // TODO - default: { - tex = storage->resources.white_tex_3d; - } break; - } + //switch (texture_hints[i]) { + // TODO + //} } break; @@ -1281,6 +1259,8 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m case ShaderLanguage::TYPE_SAMPLER2DARRAY: { // TODO } break; + + default: {} } } @@ -1448,7 +1428,16 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo if (particles->draw_order == VS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->particle_valid_histories[1]) { glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[1]); //modify the buffer, this was used 2 frames ago so it should be good enough for flushing - RasterizerGLES3Particle *particle_array = (RasterizerGLES3Particle *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 24 * sizeof(float), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT); + RasterizerGLES3Particle *particle_array; +#ifndef __EMSCRIPTEN__ + particle_array = static_cast<RasterizerGLES3Particle *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 24 * sizeof(float), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)); +#else + PoolVector<RasterizerGLES3Particle> particle_vector; + particle_vector.resize(particles->amount); + PoolVector<RasterizerGLES3Particle>::Write w = particle_vector.write(); + particle_array = w.ptr(); + glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), particle_array); +#endif SortArray<RasterizerGLES3Particle, RasterizerGLES3ParticleSort> sorter; @@ -1460,7 +1449,17 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo sorter.sort(particle_array, particles->amount); +#ifndef __EMSCRIPTEN__ glUnmapBuffer(GL_ARRAY_BUFFER); +#else + w = PoolVector<RasterizerGLES3Particle>::Write(); + particle_array = NULL; + { + PoolVector<RasterizerGLES3Particle>::Read r = particle_vector.read(); + glBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), r.ptr()); + } + particle_vector = PoolVector<RasterizerGLES3Particle>(); +#endif #ifdef DEBUG_ENABLED if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->instancing_array_wireframe_id) { glBindVertexArray(s->instancing_array_wireframe_id); // use the wireframe instancing array ID @@ -1508,6 +1507,7 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo } } break; + default: {} } } @@ -1556,8 +1556,11 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { RasterizerStorageGLES3::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES3::MultiMesh *>(e->owner); RasterizerStorageGLES3::Surface *s = static_cast<RasterizerStorageGLES3::Surface *>(e->geometry); - int amount = MAX(multi_mesh->size, multi_mesh->visible_instances); + int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); + if (amount == -1) { + amount = multi_mesh->size; + } #ifdef DEBUG_ENABLED if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->array_wireframe_id) { @@ -1826,6 +1829,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } } break; + default: {} } } @@ -2363,14 +2367,15 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G e->sort_key |= uint64_t(e->geometry->index) << RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT; e->sort_key |= uint64_t(e->instance->base_type) << RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT; - if (!p_depth_pass) { + if (e->material->last_pass != render_pass) { + e->material->last_pass = render_pass; + e->material->index = current_material_index++; + } - if (e->material->last_pass != render_pass) { - e->material->last_pass = render_pass; - e->material->index = current_material_index++; - } + e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; + e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT; - e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; + if (!p_depth_pass) { if (e->instance->gi_probe_instances.size()) { e->sort_key |= SORT_KEY_GI_PROBES_FLAG; @@ -2385,9 +2390,6 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G } e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; - } else { - e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT; - e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; } /* @@ -2533,7 +2535,7 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, false); } -void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform) { +void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog) { //store camera into ubo store_camera(p_cam_projection, state.ubo_data.projection_matrix); @@ -2584,7 +2586,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr state.ubo_data.fog_color_enabled[0] = linear_fog.r; state.ubo_data.fog_color_enabled[1] = linear_fog.g; state.ubo_data.fog_color_enabled[2] = linear_fog.b; - state.ubo_data.fog_color_enabled[3] = env->fog_enabled ? 1.0 : 0.0; + state.ubo_data.fog_color_enabled[3] = (!p_no_fog && env->fog_enabled) ? 1.0 : 0.0; Color linear_sun = env->fog_sun_color.to_linear(); state.ubo_data.fog_sun_color_amount[0] = linear_sun.r; @@ -2737,7 +2739,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform ubo_data.shadow_split_offsets[j] = li->shadow_transform[j].split; - Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse(); + Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).affine_inverse(); CameraMatrix bias; bias.set_light_bias(); @@ -3034,13 +3036,14 @@ void RasterizerSceneGLES3::_setup_reflections(RID *p_reflection_probe_cull_resul reflection_ubo.ambient[3] = rpi->probe_ptr->interior_ambient_probe_contrib; } else { Color ambient_linear; - float contrib = 0; + // FIXME: contrib was retrieved but never used, is it meant to be set as ambient[3]? (GH-20361) + //float contrib = 0; if (p_env) { ambient_linear = p_env->ambient_color.to_linear(); ambient_linear.r *= p_env->ambient_energy; ambient_linear.g *= p_env->ambient_energy; ambient_linear.b *= p_env->ambient_energy; - contrib = p_env->ambient_sky_contribution; + //contrib = p_env->ambient_sky_contribution; } reflection_ubo.ambient[0] = ambient_linear.r; @@ -3097,40 +3100,6 @@ void RasterizerSceneGLES3::_copy_screen(bool p_invalidate_color, bool p_invalida glBindVertexArray(0); } -void RasterizerSceneGLES3::_copy_to_front_buffer(Environment *env) { - - //copy to front buffer - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); - glDisable(GL_CULL_FACE); - glDisable(GL_BLEND); - glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); - - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.diffuse); - - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); - - if (!env) { - //no environment, simply convert from linear to srgb - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, true); - } else { - /* FIXME: Why are both statements equal? */ - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, true); - } - - storage->shaders.copy.bind(); - - _copy_screen(); - - //turn off everything used - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); - storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); -} - void RasterizerSceneGLES3::_copy_texture_to_front_buffer(GLuint p_texture) { //copy to front buffer @@ -3164,7 +3133,6 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p current_material_index = 0; state.used_sss = false; state.used_screen_texture = false; - //fill list for (int i = 0; i < p_cull_count; i++) { @@ -3242,6 +3210,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p } } break; + default: {} } } } @@ -3978,7 +3947,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_FILMIC); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_ACES); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINDHART_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_REINHARDT); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_REINHARD); state.tonemap_shader.set_conditional(TonemapShaderGLES3::KEEP_3D_LINEAR, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, env->auto_exposure); @@ -4065,7 +4034,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINDHART_TONEMAPPER, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL1, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL2, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL3, false); @@ -4130,7 +4099,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const state.ubo_data.screen_pixel_size[1] = 1.0 / storage->frame.current_rt->height; } - _setup_environment(env, p_cam_projection, p_cam_transform); + _setup_environment(env, p_cam_projection, p_cam_transform, p_reflection_probe.is_valid()); bool fb_cleared = false; @@ -4328,7 +4297,6 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const if (env) { switch (env->bg_mode) { case VS::ENV_BG_COLOR_SKY: - case VS::ENV_BG_SKY: sky = storage->sky_owner.getornull(env->sky); @@ -4366,6 +4334,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); break; + default: {} } } @@ -4534,7 +4503,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ RasterizerStorageGLES3::Light *light = storage->light_owner.getornull(light_instance->light); ERR_FAIL_COND(!light); - uint32_t x, y, width, height, vp_height; + uint32_t x, y, width, height; float dp_direction = 0.0; float zfar = 0; @@ -4616,7 +4585,6 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS] * bias_mult; normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult; fbo = directional_shadow.fbo; - vp_height = directional_shadow.size; } else { //set from shadow atlas @@ -4626,7 +4594,6 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); fbo = shadow_atlas->fbo; - vp_height = shadow_atlas->size; uint32_t key = shadow_atlas->shadow_owners[p_light]; @@ -4904,10 +4871,7 @@ void RasterizerSceneGLES3::initialize() { glBindBuffer(GL_UNIFORM_BUFFER, 0); render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)RenderList::DEFAULT_MAX_ELEMENTS); - if (render_list.max_elements > 1000000) - render_list.max_elements = 1000000; - if (render_list.max_elements < 1024) - render_list.max_elements = 1024; + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_elements", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_elements", PROPERTY_HINT_RANGE, "1024,1000000,1")); { //quad buffers @@ -5106,6 +5070,7 @@ void RasterizerSceneGLES3::initialize() { { uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); glGenBuffers(1, &state.immediate_buffer); glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); @@ -5180,13 +5145,13 @@ void RasterizerSceneGLES3::initialize() { void RasterizerSceneGLES3::iteration() { - shadow_filter_mode = ShadowFilterMode(int(ProjectSettings::get_singleton()->get("rendering/quality/shadows/filter_mode"))); - subsurface_scatter_follow_surface = ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/follow_surface"); - subsurface_scatter_weight_samples = ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/weight_samples"); - subsurface_scatter_quality = SubSurfaceScatterQuality(int(ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/quality"))); - subsurface_scatter_size = ProjectSettings::get_singleton()->get("rendering/quality/subsurface_scattering/scale"); + shadow_filter_mode = ShadowFilterMode(int(GLOBAL_GET("rendering/quality/shadows/filter_mode"))); + subsurface_scatter_follow_surface = GLOBAL_GET("rendering/quality/subsurface_scattering/follow_surface"); + subsurface_scatter_weight_samples = GLOBAL_GET("rendering/quality/subsurface_scattering/weight_samples"); + subsurface_scatter_quality = SubSurfaceScatterQuality(int(GLOBAL_GET("rendering/quality/subsurface_scattering/quality"))); + subsurface_scatter_size = GLOBAL_GET("rendering/quality/subsurface_scattering/scale"); - state.scene_shader.set_conditional(SceneShaderGLES3::VCT_QUALITY_HIGH, ProjectSettings::get_singleton()->get("rendering/quality/voxel_cone_tracing/high_quality")); + state.scene_shader.set_conditional(SceneShaderGLES3::VCT_QUALITY_HIGH, GLOBAL_GET("rendering/quality/voxel_cone_tracing/high_quality")); } void RasterizerSceneGLES3::finalize() { diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index cf387a69bc..4b4a0b9303 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -831,13 +831,12 @@ public: void _draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy); - void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform); + void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog = false); void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transform, bool p_use_shadows); void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_shadow_atlas); void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_reflection_atlas, Environment *p_env); void _copy_screen(bool p_invalidate_color = false, bool p_invalidate_depth = false); - void _copy_to_front_buffer(Environment *env); void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 83f731f610..c06ef805a6 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -29,8 +29,8 @@ /*************************************************************************/ #include "rasterizer_storage_gles3.h" -#include "engine.h" -#include "project_settings.h" +#include "core/engine.h" +#include "core/project_settings.h" #include "rasterizer_canvas_gles3.h" #include "rasterizer_scene_gles3.h" @@ -101,6 +101,28 @@ #define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#ifdef __EMSCRIPTEN__ +#include <emscripten/emscripten.h> + +void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) { + + /* clang-format off */ + EM_ASM({ + GLctx.getBufferSubData($0, $1, HEAPU8, $2, $3); + }, target, offset, data, size); + /* clang-format on */ +} + +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) { + + /* clang-format off */ + EM_ASM({ + GLctx.bufferSubData($0, $1, HEAPU8, $2, $3); + }, target, offset, data, size); + /* clang-format on */ +} +#endif + void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) { #ifdef GLES_OVER_GL @@ -730,7 +752,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p } }; - GLenum blit_target; + GLenum blit_target = GL_TEXTURE_2D; switch (texture->type) { case VS::TEXTURE_TYPE_2D: { @@ -948,7 +970,7 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I Image::Format real_format; Ref<Image> img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, real_format, format, internal_format, type, compressed, srgb); - GLenum blit_target; + GLenum blit_target = GL_TEXTURE_2D; switch (texture->type) { case VS::TEXTURE_TYPE_2D: { @@ -1029,7 +1051,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) PoolVector<uint8_t> data; - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1 ? -1 : 0); + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers PoolVector<uint8_t>::Write wb = data.write(); @@ -1072,7 +1094,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) uint32_t *ptr = (uint32_t *)wb.ptr(); uint32_t num_pixels = data_size / 4; - for (int ofs = 0; ofs < num_pixels; ofs++) { + for (uint32_t ofs = 0; ofs < num_pixels; ofs++) { uint32_t px = ptr[ofs]; uint32_t a = px >> 30 & 0xFF; @@ -1094,8 +1116,78 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) return Ref<Image>(img); #else - ERR_EXPLAIN("Sorry, It's not possible to obtain images back in OpenGL ES"); - ERR_FAIL_V(Ref<Image>()); + Image::Format real_format; + GLenum gl_format; + GLenum gl_internal_format; + GLenum gl_type; + bool compressed; + bool srgb; + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, srgb); + + PoolVector<uint8_t> data; + + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); + + data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers + PoolVector<uint8_t>::Write wb = data.write(); + + GLuint temp_framebuffer; + glGenFramebuffers(1, &temp_framebuffer); + + GLuint temp_color_texture; + glGenTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + + glBindTexture(GL_TEXTURE_2D, temp_color_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + print_line(itos(texture->alloc_width) + " xx " + itos(texture->alloc_height) + " -> " + itos(real_format)); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1, 1, 1, 1); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + + glViewport(0, 0, texture->alloc_width, texture->alloc_height); + + shaders.copy.bind(); + + shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb); + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + glBindVertexArray(resources.quadie_array); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindVertexArray(0); + + glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); + + shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); + + glDeleteTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &temp_framebuffer); + + wb = PoolVector<uint8_t>::Write(); + + data.resize(data_size); + + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); + if (!texture->compressed) { + img->convert(real_format); + } + + return Ref<Image>(img); #endif } @@ -1905,6 +1997,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { actions = &shaders.actions_particles; actions->uniforms = &p_shader->uniforms; } break; + case VS::SHADER_MAX: break; // Can't happen, but silences warning } Error err = shaders.compiler.compile(p_shader->mode, p_shader->code, actions, p_shader->path, gen_code); @@ -2028,6 +2121,14 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture"; } break; + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: { + + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "TextureArray"; + } break; case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: { @@ -2139,6 +2240,19 @@ Variant RasterizerStorageGLES3::material_get_param(RID p_material, const StringN if (material->params.has(p_param)) return material->params[p_param]; + return material_get_param_default(p_material, p_param); +} + +Variant RasterizerStorageGLES3::material_get_param_default(RID p_material, const StringName &p_param) const { + const Material *material = material_owner.get(p_material); + ERR_FAIL_COND_V(!material, Variant()); + + if (material->shader) { + if (material->shader->uniforms.has(p_param)) { + Vector<ShaderLanguage::ConstantNode::Value> default_value = material->shader->uniforms[p_param].default_value; + return ShaderLanguage::constant_value_to_variant(default_value, material->shader->uniforms[p_param].type); + } + } return Variant(); } @@ -3472,21 +3586,26 @@ PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, i Surface *surface = mesh->surfaces[p_surface]; - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, surface->array_byte_size, GL_MAP_READ_BIT); - - ERR_FAIL_COND_V(!data, PoolVector<uint8_t>()); - PoolVector<uint8_t> ret; ret.resize(surface->array_byte_size); + glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + { + PoolVector<uint8_t>::Write w = ret.write(); + glGetBufferSubData(GL_ARRAY_BUFFER, 0, surface->array_byte_size, w.ptr()); + } +#else + void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, surface->array_byte_size, GL_MAP_READ_BIT); + ERR_FAIL_NULL_V(data, PoolVector<uint8_t>()); { - PoolVector<uint8_t>::Write w = ret.write(); copymem(w.ptr(), data, surface->array_byte_size); } glUnmapBuffer(GL_ARRAY_BUFFER); +#endif + glBindBuffer(GL_ARRAY_BUFFER, 0); return ret; } @@ -3499,22 +3618,26 @@ PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_m ERR_FAIL_COND_V(surface->index_array_len == 0, PoolVector<uint8_t>()); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); - void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT); - - ERR_FAIL_COND_V(!data, PoolVector<uint8_t>()); - PoolVector<uint8_t> ret; ret.resize(surface->index_array_byte_size); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + { + PoolVector<uint8_t>::Write w = ret.write(); + glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, w.ptr()); + } +#else + void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT); + ERR_FAIL_NULL_V(data, PoolVector<uint8_t>()); { - PoolVector<uint8_t>::Write w = ret.write(); copymem(w.ptr(), data, surface->index_array_byte_size); } - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); +#endif + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); return ret; } @@ -3555,23 +3678,26 @@ Vector<PoolVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shap for (int i = 0; i < mesh->surfaces[p_surface]->blend_shapes.size(); i++) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->surfaces[p_surface]->blend_shapes[i].vertex_id); - void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, GL_MAP_READ_BIT); - - ERR_FAIL_COND_V(!data, Vector<PoolVector<uint8_t> >()); - PoolVector<uint8_t> ret; ret.resize(mesh->surfaces[p_surface]->array_byte_size); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->surfaces[p_surface]->blend_shapes[i].vertex_id); +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + { + PoolVector<uint8_t>::Write w = ret.write(); + glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, w.ptr()); + } +#else + void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, GL_MAP_READ_BIT); + ERR_FAIL_COND_V(!data, Vector<PoolVector<uint8_t> >()); { - PoolVector<uint8_t>::Write w = ret.write(); copymem(w.ptr(), data, mesh->surfaces[p_surface]->array_byte_size); } + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); +#endif bsarr.push_back(ret); - - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); } return bsarr; @@ -4044,35 +4170,37 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances multimesh->data.resize(format_floats * p_instances); + float *dataptr = multimesh->data.ptrw(); + for (int i = 0; i < p_instances * format_floats; i += format_floats) { int color_from = 0; int custom_data_from = 0; if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) { - multimesh->data.write[i + 0] = 1.0; - multimesh->data.write[i + 1] = 0.0; - multimesh->data.write[i + 2] = 0.0; - multimesh->data.write[i + 3] = 0.0; - multimesh->data.write[i + 4] = 0.0; - multimesh->data.write[i + 5] = 1.0; - multimesh->data.write[i + 6] = 0.0; - multimesh->data.write[i + 7] = 0.0; + dataptr[i + 0] = 1.0; + dataptr[i + 1] = 0.0; + dataptr[i + 2] = 0.0; + dataptr[i + 3] = 0.0; + dataptr[i + 4] = 0.0; + dataptr[i + 5] = 1.0; + dataptr[i + 6] = 0.0; + dataptr[i + 7] = 0.0; color_from = 8; custom_data_from = 8; } else { - multimesh->data.write[i + 0] = 1.0; - multimesh->data.write[i + 1] = 0.0; - multimesh->data.write[i + 2] = 0.0; - multimesh->data.write[i + 3] = 0.0; - multimesh->data.write[i + 4] = 0.0; - multimesh->data.write[i + 5] = 1.0; - multimesh->data.write[i + 6] = 0.0; - multimesh->data.write[i + 7] = 0.0; - multimesh->data.write[i + 8] = 0.0; - multimesh->data.write[i + 9] = 0.0; - multimesh->data.write[i + 10] = 1.0; - multimesh->data.write[i + 11] = 0.0; + dataptr[i + 0] = 1.0; + dataptr[i + 1] = 0.0; + dataptr[i + 2] = 0.0; + dataptr[i + 3] = 0.0; + dataptr[i + 4] = 0.0; + dataptr[i + 5] = 1.0; + dataptr[i + 6] = 0.0; + dataptr[i + 7] = 0.0; + dataptr[i + 8] = 0.0; + dataptr[i + 9] = 0.0; + dataptr[i + 10] = 1.0; + dataptr[i + 11] = 0.0; color_from = 12; custom_data_from = 12; } @@ -4087,14 +4215,14 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances } cu; cu.colu = 0xFFFFFFFF; - multimesh->data.write[i + color_from + 0] = cu.colf; + dataptr[i + color_from + 0] = cu.colf; custom_data_from = color_from + 1; } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) { - multimesh->data.write[i + color_from + 0] = 1.0; - multimesh->data.write[i + color_from + 1] = 1.0; - multimesh->data.write[i + color_from + 2] = 1.0; - multimesh->data.write[i + color_from + 3] = 1.0; + dataptr[i + color_from + 0] = 1.0; + dataptr[i + color_from + 1] = 1.0; + dataptr[i + color_from + 2] = 1.0; + dataptr[i + color_from + 3] = 1.0; custom_data_from = color_from + 4; } @@ -4108,13 +4236,13 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances } cu; cu.colu = 0; - multimesh->data.write[i + custom_data_from + 0] = cu.colf; + dataptr[i + custom_data_from + 0] = cu.colf; } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) { - multimesh->data.write[i + custom_data_from + 0] = 0.0; - multimesh->data.write[i + custom_data_from + 1] = 0.0; - multimesh->data.write[i + custom_data_from + 2] = 0.0; - multimesh->data.write[i + custom_data_from + 3] = 0.0; + dataptr[i + custom_data_from + 0] = 0.0; + dataptr[i + custom_data_from + 1] = 0.0; + dataptr[i + custom_data_from + 2] = 0.0; + dataptr[i + custom_data_from + 3] = 0.0; } } @@ -4948,6 +5076,7 @@ void RasterizerStorageGLES3::light_set_param(RID p_light, VS::LightParam p_param light->version++; light->instance_change_notify(); } break; + default: {} } light->param[p_param] = p_value; @@ -5001,6 +5130,9 @@ void RasterizerStorageGLES3::light_set_reverse_cull_face_mode(RID p_light, bool ERR_FAIL_COND(!light); light->reverse_cull = p_enabled; + + light->version++; + light->instance_change_notify(); } void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) { @@ -5272,6 +5404,9 @@ void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_ reflection_probe->instance_change_notify(); } +void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution) { +} + AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const { const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); ERR_FAIL_COND_V(!reflection_probe, AABB()); @@ -5970,9 +6105,21 @@ AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, AABB()); + const float *data; glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); - float *data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT); +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + PoolVector<uint8_t> vector; + vector.resize(particles->amount * 16 * 6); + { + PoolVector<uint8_t>::Write w = vector.write(); + glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, w.ptr()); + } + PoolVector<uint8_t>::Read r = vector.read(); + data = reinterpret_cast<const float *>(r.ptr()); +#else + data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT); +#endif AABB aabb; Transform inv = particles->emission_transform.affine_inverse(); @@ -5989,7 +6136,13 @@ AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { aabb.expand_to(pos); } +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + r = PoolVector<uint8_t>::Read(); + vector = PoolVector<uint8_t>(); +#else glUnmapBuffer(GL_ARRAY_BUFFER); +#endif + glBindBuffer(GL_ARRAY_BUFFER, 0); float longest_axis = 0; @@ -6812,7 +6965,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); glDisable(GL_SCISSOR_TEST); glColorMask(1, 1, 1, 1); - if (rt->buffers.active == false) { + if (!rt->buffers.active) { glDepthMask(GL_TRUE); } @@ -7338,7 +7491,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) { GIProbeData *gi_probe_data = gi_probe_data_owner.get(p_rid); glDeleteTextures(1, &gi_probe_data->tex_id); - gi_probe_owner.free(p_rid); + gi_probe_data_owner.free(p_rid); memdelete(gi_probe_data); } else if (lightmap_capture_data_owner.owns(p_rid)) { @@ -7346,7 +7499,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) { LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid); lightmap_capture->instance_remove_deps(); - gi_probe_owner.free(p_rid); + lightmap_capture_data_owner.free(p_rid); memdelete(lightmap_capture); } else if (canvas_occluder_owner.owns(p_rid)) { @@ -7655,6 +7808,8 @@ void RasterizerStorageGLES3::initialize() { { //transform feedback buffers uint32_t xf_feedback_size = GLOBAL_DEF_RST("rendering/limits/buffers/blend_shape_max_buffer_size_kb", 4096); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/blend_shape_max_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/blend_shape_max_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); + for (int i = 0; i < 2; i++) { glGenBuffers(1, &resources.transform_feedback_buffers[i]); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index b74dd77e26..8c26e09037 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -31,17 +31,24 @@ #ifndef RASTERIZERSTORAGEGLES3_H #define RASTERIZERSTORAGEGLES3_H -#include "self_list.h" +#include "core/self_list.h" #include "servers/visual/rasterizer.h" #include "servers/visual/shader_language.h" #include "shader_compiler_gles3.h" #include "shader_gles3.h" + #include "shaders/blend_shape.glsl.gen.h" #include "shaders/canvas.glsl.gen.h" #include "shaders/copy.glsl.gen.h" #include "shaders/cubemap_filter.glsl.gen.h" #include "shaders/particles.glsl.gen.h" +// WebGL 2.0 has no MapBufferRange/UnmapBuffer, but offers a non-ES style BufferSubData API instead. +#ifdef __EMSCRIPTEN__ +void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +#endif + class RasterizerCanvasGLES3; class RasterizerSceneGLES3; @@ -582,6 +589,7 @@ public: virtual void material_set_param(RID p_material, const StringName &p_param, const Variant &p_value); virtual Variant material_get_param(RID p_material, const StringName &p_param) const; + virtual Variant material_get_param_default(RID p_material, const StringName &p_param) const; virtual void material_set_line_width(RID p_material, float p_width); virtual void material_set_next_pass(RID p_material, RID p_next_material); @@ -689,7 +697,7 @@ public: } }; - class MultiMesh; + struct MultiMesh; struct Mesh : public GeometryOwner { @@ -1003,6 +1011,7 @@ public: virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); + virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); virtual AABB reflection_probe_get_aabb(RID p_probe) const; virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index a78a392cbd..be36b41417 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -30,7 +30,8 @@ #include "shader_compiler_gles3.h" -#include "os/os.h" +#include "core/os/os.h" +#include "core/project_settings.h" #define SL ShaderLanguage @@ -78,6 +79,12 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_SAMPLER2D: return 16; case SL::TYPE_ISAMPLER2D: return 16; case SL::TYPE_USAMPLER2D: return 16; + case SL::TYPE_SAMPLER2DARRAY: return 16; + case SL::TYPE_ISAMPLER2DARRAY: return 16; + case SL::TYPE_USAMPLER2DARRAY: return 16; + case SL::TYPE_SAMPLER3D: return 16; + case SL::TYPE_ISAMPLER3D: return 16; + case SL::TYPE_USAMPLER3D: return 16; case SL::TYPE_SAMPLERCUBE: return 16; } @@ -111,6 +118,12 @@ static int _get_datatype_alignment(SL::DataType p_type) { case SL::TYPE_SAMPLER2D: return 16; case SL::TYPE_ISAMPLER2D: return 16; case SL::TYPE_USAMPLER2D: return 16; + case SL::TYPE_SAMPLER2DARRAY: return 16; + case SL::TYPE_ISAMPLER2DARRAY: return 16; + case SL::TYPE_USAMPLER2DARRAY: return 16; + case SL::TYPE_SAMPLER3D: return 16; + case SL::TYPE_ISAMPLER3D: return 16; + case SL::TYPE_USAMPLER3D: return 16; case SL::TYPE_SAMPLERCUBE: return 16; } @@ -859,7 +872,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer"; + actions[VS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth"; actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; + actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; //for light actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view"; @@ -901,12 +916,24 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); + + if (!force_lambert) { + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; + } + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + bool force_blinn = GLOBAL_GET("rendering/quality/shading/force_blinn_over_ggx"); + + if (!force_blinn) { + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; + } else { + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_BLINN\n"; + } + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index 7a32057741..1f903b8935 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -31,7 +31,7 @@ #ifndef SHADERCOMPILERGLES3_H #define SHADERCOMPILERGLES3_H -#include "pair.h" +#include "core/pair.h" #include "servers/visual/shader_language.h" #include "servers/visual/shader_types.h" #include "servers/visual_server.h" diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 007600bb42..799179e8d4 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -30,7 +30,7 @@ #include "shader_gles3.h" -#include "print_string.h" +#include "core/print_string.h" //#define DEBUG_OPENGL @@ -122,6 +122,11 @@ bool ShaderGLES3::bind() { ERR_FAIL_COND_V(!version, false); + if (!version->ok) { //broken, unable to bind (do not throw error, you saw it before already when it failed compilation). + glUseProgram(0); + return false; + } + glUseProgram(version->id); DEBUG_TEST_ERROR("Use Program"); diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h index 996655615e..0d360e8453 100644 --- a/drivers/gles3/shader_gles3.h +++ b/drivers/gles3/shader_gles3.h @@ -31,7 +31,10 @@ #ifndef SHADER_GLES3_H #define SHADER_GLES3_H -#include <stdio.h> +#include "core/hash_map.h" +#include "core/map.h" +#include "core/math/camera_matrix.h" +#include "core/variant.h" #include "platform_config.h" #ifndef GLES3_INCLUDE_H @@ -40,10 +43,7 @@ #include GLES3_INCLUDE_H #endif -#include "camera_matrix.h" -#include "hash_map.h" -#include "map.h" -#include "variant.h" +#include <stdio.h> /** @author Juan Linietsky <reduzio@gmail.com> @@ -128,11 +128,13 @@ private: Vector<GLint> texture_uniform_locations; uint32_t code_version; bool ok; - Version() { - code_version = 0; - ok = false; - uniform_location = NULL; - } + Version() : + id(0), + vert_id(0), + frag_id(0), + uniform_location(NULL), + code_version(0), + ok(false) {} }; Version *version; @@ -336,6 +338,7 @@ public: } uint32_t get_version() const { return new_conditional_version.version; } + _FORCE_INLINE_ bool is_version_valid() const { return version && version->ok; } void set_uniform_camera(int p_idx, const CameraMatrix &p_mat) { diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index f1811fa7b5..27fd1514e7 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -20,3 +20,4 @@ if 'GLES3_GLSL' in env['BUILDERS']: env.GLES3_GLSL('exposure.glsl'); env.GLES3_GLSL('tonemap.glsl'); env.GLES3_GLSL('particles.glsl'); + env.GLES3_GLSL('lens_distorted.glsl'); diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 53f563303a..8e8b693eb2 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -120,12 +120,12 @@ void main() { vec4 color = color_attrib; #ifdef USE_INSTANCING - mat4 extra_matrix2 = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); + mat4 extra_matrix_instance = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0))); color *= instance_color; vec4 instance_custom = instance_custom_data; #else - mat4 extra_matrix2 = extra_matrix; + mat4 extra_matrix_instance = extra_matrix; vec4 instance_custom = vec4(0.0); #endif @@ -157,7 +157,7 @@ void main() { #endif -#define extra_matrix extra_matrix2 +#define extra_matrix extra_matrix_instance { /* clang-format off */ @@ -182,7 +182,6 @@ VERTEX_SHADER_CODE color_interp = color; #ifdef USE_PIXEL_SNAP - outvec.xy = floor(outvec + 0.5).xy; #endif @@ -246,8 +245,8 @@ VERTEX_SHADER_CODE pos = outvec.xy; #endif - local_rot.xy = normalize((modelview_matrix * (extra_matrix * vec4(1.0, 0.0, 0.0, 0.0))).xy); - local_rot.zw = normalize((modelview_matrix * (extra_matrix * vec4(0.0, 1.0, 0.0, 0.0))).xy); + local_rot.xy = normalize((modelview_matrix * (extra_matrix_instance * vec4(1.0, 0.0, 0.0, 0.0))).xy); + local_rot.zw = normalize((modelview_matrix * (extra_matrix_instance * vec4(0.0, 1.0, 0.0, 0.0))).xy); #ifdef USE_TEXTURE_RECT local_rot.xy *= sign(src_rect.z); local_rot.zw *= sign(src_rect.w); diff --git a/drivers/gles3/shaders/lens_distorted.glsl b/drivers/gles3/shaders/lens_distorted.glsl new file mode 100644 index 0000000000..7b9d0b347f --- /dev/null +++ b/drivers/gles3/shaders/lens_distorted.glsl @@ -0,0 +1,64 @@ +/* clang-format off */ +[vertex] + +layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ + +uniform vec2 offset; +uniform vec2 scale; + +out vec2 uv_interp; + +void main() { + + uv_interp = vertex_attrib.xy * 2.0 - 1.0; + + vec2 v = vertex_attrib.xy * scale + offset; + gl_Position = vec4(v, 0.0, 1.0); +} + +/* clang-format off */ +[fragment] + +uniform sampler2D source; //texunit:0 +/* clang-format on */ + +uniform vec2 eye_center; +uniform float k1; +uniform float k2; +uniform float upscale; +uniform float aspect_ratio; + +in vec2 uv_interp; + +layout(location = 0) out vec4 frag_color; + +void main() { + vec2 coords = uv_interp; + vec2 offset = coords - eye_center; + + // take aspect ratio into account + offset.y /= aspect_ratio; + + // distort + vec2 offset_sq = offset * offset; + float radius_sq = offset_sq.x + offset_sq.y; + float radius_s4 = radius_sq * radius_sq; + float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); + offset *= distortion_scale; + + // reapply aspect ratio + offset.y *= aspect_ratio; + + // add our eye center back in + coords = offset + eye_center; + coords /= upscale; + + // and check our color + if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { + frag_color = vec4(0.0, 0.0, 0.0, 1.0); + } else { + coords = (coords + vec2(1.0)) / vec2(2.0); + frag_color = textureLod(source, coords, 0.0); + } +} diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 12cbe02d0c..91ab34f775 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -3,6 +3,8 @@ #define M_PI 3.14159265359 +#define SHADER_IS_SRGB false + /* from VisualServer: @@ -514,6 +516,7 @@ VERTEX_SHADER_CODE /* clang-format off */ [fragment] + /* texture unit usage, N is max_texture_unity-N 1-skeleton @@ -533,6 +536,7 @@ uniform highp mat4 world_transform; /* clang-format on */ #define M_PI 3.14159265359 +#define SHADER_IS_SRGB false /* Varyings */ @@ -916,13 +920,14 @@ float GTR1(float NdotH, float a) { return (a2 - 1.0) / (M_PI * log(a2) * t); } -vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) { - float dielectric = (0.034 * 2.0) * specular; - // energy conservation - return mix(vec3(dielectric), albedo, metallic); // TODO: reference? +vec3 F0(float metallic, float specular, vec3 albedo) { + float dielectric = 0.16 * specular * specular; + // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; + // see https://google.github.io/filament/Filament.md.html + return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light) { #if defined(USE_LIGHT_SHADER_CODE) // light is written by the light shader @@ -1020,16 +1025,27 @@ LIGHT_SHADER_CODE #if defined(SPECULAR_BLINN) + //normalized blinn vec3 H = normalize(V + L); float cNdotH = max(dot(N, H), 0.0); - float intensity = pow(cNdotH, (1.0 - roughness) * 256.0); + float cVdotH = max(dot(V, H), 0.0); + float cLdotH = max(dot(L, H), 0.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float blinn = pow(cNdotH, shininess); + blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + float intensity = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); + specular_light += light_color * intensity * specular_blob_intensity * attenuation; #elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L, N)); float cRdotV = max(0.0, dot(R, V)); - float intensity = pow(cRdotV, (1.0 - roughness) * 256.0); + float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; + float phong = pow(cRdotV, shininess); + phong *= (shininess + 8.0) / (8.0 * 3.141592654); + float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); + specular_light += light_color * intensity * specular_blob_intensity * attenuation; #elif defined(SPECULAR_TOON) @@ -1054,11 +1070,10 @@ LIGHT_SHADER_CODE #if defined(LIGHT_USE_ANISOTROPY) + float alpha = roughness * roughness; float aspect = sqrt(1.0 - anisotropy * 0.9); - float rx = roughness / aspect; - float ry = roughness * aspect; - float ax = rx * rx; - float ay = ry * ry; + float ax = alpha / aspect; + float ay = alpha * aspect; float XdotH = dot(T, H); float YdotH = dot(B, H); float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); @@ -1070,11 +1085,11 @@ LIGHT_SHADER_CODE float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); #endif // F - float F0 = 1.0; // FIXME + vec3 f0 = F0(metallic, specular, diffuse_color); float cLdotH5 = SchlickFresnel(cLdotH); - float F = mix(cLdotH5, 1.0, F0); + vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); - float specular_brdf_NL = cNdotL * D * F * G; + vec3 specular_brdf_NL = cNdotL * D * F * G; specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #endif @@ -1121,8 +1136,9 @@ float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 p avg += textureProj(shadow, vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); return avg * (1.0 / 13.0); +#endif -#elif defined(SHADOW_MODE_PCF_5) +#ifdef SHADOW_MODE_PCF_5 float avg = textureProj(shadow, vec4(pos, depth, 1.0)); avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); @@ -1131,7 +1147,9 @@ float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 p avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); return avg * (1.0 / 5.0); -#else +#endif + +#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) return textureProj(shadow, vec4(pos, depth, 1.0)); @@ -1173,7 +1191,7 @@ vec3 light_transmittance(float translucency,vec3 light_vec, vec3 normal, vec3 po } #endif -void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex; float light_length = length(light_rel_vec); @@ -1227,10 +1245,10 @@ void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi light_attenuation *= mix(omni_lights[idx].shadow_color_contact.rgb, vec3(1.0), shadow); } #endif //SHADOWS_DISABLED - light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, omni_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, omni_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, rim * omni_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, omni_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, omni_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * omni_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); } -void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex; float light_length = length(light_rel_vec); @@ -1262,7 +1280,7 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi } #endif //SHADOWS_DISABLED - light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, spot_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, spot_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, rim * spot_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, spot_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, spot_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * spot_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); } void reflection_process(int idx, vec3 vertex, vec3 normal, vec3 binormal, vec3 tangent, float roughness, float anisotropy, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { @@ -1322,7 +1340,7 @@ void reflection_process(int idx, vec3 vertex, vec3 normal, vec3 binormal, vec3 t reflection_accum += reflection; } -#ifndef USE_LIGHTMAP +#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE) if (reflections[idx].ambient.a > 0.0) { //compute ambient using skybox vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal, 0.0)).xyz; @@ -1877,7 +1895,7 @@ FRAGMENT_SHADER_CODE specular_light *= mix(vec3(1.0), light_attenuation, specular_light_interp.a); #else - light_compute(normal, -light_direction_attenuation.xyz, eye_vec, binormal, tangent, light_color_energy.rgb, light_attenuation, albedo, transmission, light_params.z * specular_blob_intensity, roughness, metallic, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, -light_direction_attenuation.xyz, eye_vec, binormal, tangent, light_color_energy.rgb, light_attenuation, albedo, transmission, light_params.z * specular_blob_intensity, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); #endif #endif //#USE_LIGHT_DIRECTIONAL @@ -1939,7 +1957,7 @@ FRAGMENT_SHADER_CODE } else { specular_light += env_reflection_light; } -#ifndef USE_LIGHTMAP +#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE) if (ambient_accum.a > 0.0) { ambient_light = ambient_accum.rgb / ambient_accum.a; } @@ -1951,11 +1969,11 @@ FRAGMENT_SHADER_CODE #else for (int i = 0; i < omni_light_count; i++) { - light_process_omni(omni_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); + light_process_omni(omni_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); } for (int i = 0; i < spot_light_count; i++) { - light_process_spot(spot_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); + light_process_spot(spot_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); } #endif //USE_VERTEX_LIGHTING @@ -1976,7 +1994,7 @@ FRAGMENT_SHADER_CODE diffuse_light *= ao_light_affect; #endif - //energy conservation + // base color remapping diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point ambient_light *= 1.0 - metallic; @@ -1993,10 +2011,10 @@ FRAGMENT_SHADER_CODE vec4 r = roughness * c0 + c1; float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0); float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; - vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo); - specular_light *= AB.x * specular_color + AB.y; + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; #endif } @@ -2035,7 +2053,7 @@ FRAGMENT_SHADER_CODE emission = emission * rev_amount + fog_color * fog_amount; ambient_light *= rev_amount; - specular_light *rev_amount; + specular_light *= rev_amount; diffuse_light *= rev_amount; } diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index e4aa8d5730..80ad003c80 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -124,13 +124,16 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { #endif vec3 tonemap_filmic(vec3 color, float white) { - const float A = 0.15f; - const float B = 0.50f; + // exposure bias: input scale (color *= bias, white *= bias) to make the brighness consistent with other tonemappers + // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values) + // has no effect on the curve's general shape or visual properties + const float exposure_bias = 2.0f; + const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance + const float B = 0.30f * exposure_bias; const float C = 0.10f; const float D = 0.20f; - const float E = 0.02f; + const float E = 0.01f; const float F = 0.30f; - const float W = 11.2f; vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; float white_tonemapped = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F; @@ -139,10 +142,11 @@ vec3 tonemap_filmic(vec3 color, float white) { } vec3 tonemap_aces(vec3 color, float white) { - const float A = 2.51f; - const float B = 0.03f; - const float C = 2.43f; - const float D = 0.59f; + const float exposure_bias = 0.85f; + const float A = 2.51f * exposure_bias * exposure_bias; + const float B = 0.03f * exposure_bias; + const float C = 2.43f * exposure_bias * exposure_bias; + const float D = 0.59f * exposure_bias; const float E = 0.14f; vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E); @@ -151,8 +155,8 @@ vec3 tonemap_aces(vec3 color, float white) { return clamp(color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f)); } -vec3 tonemap_reindhart(vec3 color, float white) { - return clamp((color) / (1.0f + color) * (1.0f + (color / (white))), vec3(0.0f), vec3(1.0f)); // whitepoint is probably not in linear space here! +vec3 tonemap_reinhard(vec3 color, float white) { + return clamp((white * color + color) / (color * white + white), vec3(0.0f), vec3(1.0f)); } vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped input in range [0;1] @@ -161,8 +165,8 @@ vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped } vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color -#ifdef USE_REINDHART_TONEMAPPER - return tonemap_reindhart(color, white); +#ifdef USE_REINHARD_TONEMAPPER + return tonemap_reinhard(color, white); #endif #ifdef USE_FILMIC_TONEMAPPER @@ -173,7 +177,7 @@ vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always o return tonemap_aces(color, white); #endif - return clamp(color, vec3(0.0f), vec3(1.0f)); // no other seleced -> linear + return clamp(color, vec3(0.0f), vec3(1.0f)); // no other selected -> linear } vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels diff --git a/drivers/png/SCsub b/drivers/png/SCsub index 39480351a6..22fb1817d1 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -26,14 +26,24 @@ if env['builtin_libpng']: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - env_png.add_source_files(env.drivers_sources, thirdparty_sources) env_png.Append(CPPPATH=[thirdparty_dir]) + # Needed for drivers includes and in platform/javascript + env.Append(CPPPATH=[thirdparty_dir]) # Currently .ASM filter_neon.S does not compile on NT. import os - if ("neon_enabled" in env and env["neon_enabled"]) and os.name != "nt": + use_neon = "neon_enabled" in env and env["neon_enabled"] and os.name != "nt" + if use_neon: env_png.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=2"]) - env_neon = env_png.Clone() + else: + env_png.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=0"]) + + env_thirdparty = env_png.Clone() + env_thirdparty.disable_warnings() + env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) + + if use_neon: + env_neon = env_thirdparty.Clone() if "S_compiler" in env: env_neon['CC'] = env['S_compiler'] neon_sources = [] @@ -41,8 +51,6 @@ if env['builtin_libpng']: neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon_intrinsics.c")) neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon.S")) env.drivers_sources += neon_sources - else: - env_png.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=0"]) # Godot source files env_png.add_source_files(env.drivers_sources, "*.cpp") diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index b08688892e..a4ea889d3b 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -30,8 +30,8 @@ #include "image_loader_png.h" -#include "os/os.h" -#include "print_string.h" +#include "core/os/os.h" +#include "core/print_string.h" #include <string.h> @@ -227,10 +227,7 @@ static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t p_len PNGReadStatus *rstatus; rstatus = (PNGReadStatus *)png_get_io_ptr(png_ptr); - png_size_t to_read = p_length; - if (rstatus->size >= 0) { - to_read = MIN(p_length, rstatus->size - rstatus->offset); - } + png_size_t to_read = MIN(p_length, rstatus->size - rstatus->offset); memcpy(data, &rstatus->image[rstatus->offset], to_read); rstatus->offset += to_read; diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index 48f48e6bea..5dff7e3902 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.h @@ -31,7 +31,7 @@ #ifndef IMAGE_LOADER_PNG_H #define IMAGE_LOADER_PNG_H -#include "io/image_loader.h" +#include "core/io/image_loader.h" #include <png.h> diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index 270ae36e1e..c5729f70b2 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -31,8 +31,8 @@ #include "resource_saver_png.h" #include "core/image.h" -#include "os/file_access.h" -#include "project_settings.h" +#include "core/os/file_access.h" +#include "core/project_settings.h" #include "scene/resources/texture.h" #include <png.h> diff --git a/drivers/png/resource_saver_png.h b/drivers/png/resource_saver_png.h index 109b4801da..34950f6723 100644 --- a/drivers/png/resource_saver_png.h +++ b/drivers/png/resource_saver_png.h @@ -31,8 +31,8 @@ #ifndef RESOURCE_SAVER_PNG_H #define RESOURCE_SAVER_PNG_H -#include "image.h" -#include "io/resource_saver.h" +#include "core/image.h" +#include "core/io/resource_saver.h" class ResourceSaverPNG : public ResourceFormatSaver { public: diff --git a/drivers/pulseaudio/SCsub b/drivers/pulseaudio/SCsub index ee39fd2631..28b315ae66 100644 --- a/drivers/pulseaudio/SCsub +++ b/drivers/pulseaudio/SCsub @@ -3,5 +3,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 744b3a35e6..d78316945f 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -32,10 +32,8 @@ #ifdef PULSEAUDIO_ENABLED -#include <pulse/pulseaudio.h> - -#include "os/os.h" -#include "project_settings.h" +#include "core/os/os.h" +#include "core/project_settings.h" void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) { AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata; @@ -45,10 +43,13 @@ void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) { case PA_CONTEXT_FAILED: ad->pa_ready = -1; break; - case PA_CONTEXT_READY: ad->pa_ready = 1; break; + default: + // TODO: Check if we want to handle some of the other + // PA context states like PA_CONTEXT_UNCONNECTED. + break; } } @@ -342,7 +343,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { unsigned int out_idx = 0; for (unsigned int i = 0; i < ad->buffer_frames; i++) { - for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) { + for (int j = 0; j < ad->pa_map.channels - 1; j++) { ad->samples_out.write[out_idx++] = ad->samples_in[in_idx++] >> 16; } uint32_t l = ad->samples_in[in_idx++]; @@ -612,20 +613,18 @@ Error AudioDriverPulseAudio::capture_init_device() { break; } - print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels"); - pa_sample_spec spec; spec.format = PA_SAMPLE_S16LE; spec.channels = pa_rec_map.channels; spec.rate = mix_rate; - int latency = 30; - input_buffer_frames = closest_power_of_2(latency * mix_rate / 1000); - int buffer_size = input_buffer_frames * spec.channels; + int input_latency = 30; + int input_buffer_frames = closest_power_of_2(input_latency * mix_rate / 1000); + int input_buffer_size = input_buffer_frames * spec.channels; pa_buffer_attr attr; - attr.fragsize = buffer_size * sizeof(int16_t); + attr.fragsize = input_buffer_size * sizeof(int16_t); pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map); if (pa_rec_str == NULL) { @@ -641,9 +640,10 @@ Error AudioDriverPulseAudio::capture_init_device() { ERR_FAIL_V(ERR_CANT_OPEN); } - input_buffer.resize(input_buffer_frames * 8); - input_position = 0; - input_size = 0; + input_buffer_init(input_buffer_frames); + + print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels"); + print_verbose("PulseAudio: input buffer frames: " + itos(input_buffer_frames) + " calculated latency: " + itos(input_buffer_frames * 1000 / mix_rate) + "ms"); return OK; } @@ -759,7 +759,6 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() { mix_rate = 0; buffer_frames = 0; - input_buffer_frames = 0; pa_buffer_size = 0; channels = 0; pa_ready = 0; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index f8358a452b..d8bab841ff 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -64,7 +64,6 @@ class AudioDriverPulseAudio : public AudioDriver { unsigned int mix_rate; unsigned int buffer_frames; - unsigned int input_buffer_frames; unsigned int pa_buffer_size; int channels; int pa_ready; diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index c6d36a5749..9f5d9c1abf 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -31,11 +31,11 @@ #include "register_driver_types.h" #include "core/math/geometry.h" -#include "png/image_loader_png.h" -#include "png/resource_saver_png.h" +#include "drivers/png/image_loader_png.h" +#include "drivers/png/resource_saver_png.h" #ifdef TOOLS_ENABLED -#include "convex_decomp/b2d_decompose.h" +#include "drivers/convex_decomp/b2d_decompose.h" #endif #ifdef TOOLS_ENABLED diff --git a/drivers/rtaudio/SCsub b/drivers/rtaudio/SCsub index 2b0a602965..285658073c 100644 --- a/drivers/rtaudio/SCsub +++ b/drivers/rtaudio/SCsub @@ -11,9 +11,12 @@ thirdparty_sources = [ ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env.add_source_files(env.drivers_sources, thirdparty_sources) env.Append(CPPPATH=[thirdparty_dir]) +env_thirdparty = env.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) + # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp index 69830b542b..bc6ceb1e7e 100644 --- a/drivers/rtaudio/audio_driver_rtaudio.cpp +++ b/drivers/rtaudio/audio_driver_rtaudio.cpp @@ -30,8 +30,8 @@ #include "audio_driver_rtaudio.h" -#include "os/os.h" -#include "project_settings.h" +#include "core/os/os.h" +#include "core/project_settings.h" #ifdef RTAUDIO_ENABLED @@ -114,11 +114,12 @@ Error AudioDriverRtAudio::init() { unsigned int buffer_frames = closest_power_of_2(latency * mix_rate / 1000); print_verbose("Audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); - short int tries = 2; + short int tries = 4; - while (tries >= 0) { + while (tries > 0) { switch (speaker_mode) { case SPEAKER_MODE_STEREO: parameters.nChannels = 2; break; + case SPEAKER_SURROUND_31: parameters.nChannels = 4; break; case SPEAKER_SURROUND_51: parameters.nChannels = 6; break; case SPEAKER_SURROUND_71: parameters.nChannels = 8; break; }; @@ -128,12 +129,14 @@ Error AudioDriverRtAudio::init() { active = true; break; - } catch (RtAudioError &e) { + } catch (RtAudioError) { // try with less channels ERR_PRINT("Unable to open audio, retrying with fewer channels..."); switch (speaker_mode) { - case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_MODE_STEREO; break; + case SPEAKER_MODE_STEREO: break; // Required to silence unhandled enum value warning. + case SPEAKER_SURROUND_31: speaker_mode = SPEAKER_MODE_STEREO; break; + case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_SURROUND_31; break; case SPEAKER_SURROUND_71: speaker_mode = SPEAKER_SURROUND_51; break; } diff --git a/drivers/unix/SCsub b/drivers/unix/SCsub index ada8255580..4888f56099 100644 --- a/drivers/unix/SCsub +++ b/drivers/unix/SCsub @@ -5,5 +5,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") env["check_c_headers"] = [ [ "mntent.h", "HAVE_MNTENT" ] ] - -Export('env') diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index 5a4be6df4f..929e67faa9 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -32,18 +32,19 @@ #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) -#ifndef ANDROID_ENABLED -#include <sys/statvfs.h> -#endif - #include "core/list.h" -#include "os/memory.h" -#include "print_string.h" +#include "core/os/memory.h" +#include "core/print_string.h" + #include <errno.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#ifndef ANDROID_ENABLED +#include <sys/statvfs.h> +#endif + #ifdef HAVE_MNTENT #include <mntent.h> #endif @@ -59,7 +60,7 @@ Error DirAccessUnix::list_dir_begin() { //char real_current_dir_name[2048]; //is this enough?! //getcwd(real_current_dir_name,2048); - //chdir(curent_path.utf8().get_data()); + //chdir(current_path.utf8().get_data()); dir_stream = opendir(current_dir.utf8().get_data()); //chdir(real_current_dir_name); if (!dir_stream) @@ -308,7 +309,7 @@ Error DirAccessUnix::change_dir(String p_dir) { // prev_dir is the directory we are changing out of String prev_dir; char real_current_dir_name[2048]; - getcwd(real_current_dir_name, 2048); + ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG); if (prev_dir.parse_utf8(real_current_dir_name)) prev_dir = real_current_dir_name; //no utf8, maybe latin? @@ -329,7 +330,7 @@ Error DirAccessUnix::change_dir(String p_dir) { // the directory exists, so set current_dir to try_dir current_dir = try_dir; - chdir(prev_dir.utf8().get_data()); + ERR_FAIL_COND_V(chdir(prev_dir.utf8().get_data()) != 0, ERR_BUG); return OK; } @@ -390,7 +391,7 @@ size_t DirAccessUnix::get_space_left() { return vfs.f_bfree * vfs.f_bsize; #else -#warning THIS IS BROKEN + // FIXME: Implement this. return 0; #endif }; @@ -404,7 +405,7 @@ DirAccessUnix::DirAccessUnix() { // set current directory to an absolute path of the current directory char real_current_dir_name[2048]; - getcwd(real_current_dir_name, 2048); + ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == NULL); if (current_dir.parse_utf8(real_current_dir_name)) current_dir = real_current_dir_name; diff --git a/drivers/unix/dir_access_unix.h b/drivers/unix/dir_access_unix.h index a55acdbd34..26978930bd 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -33,16 +33,17 @@ #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) +#include "core/os/dir_access.h" + #include <dirent.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> -#include "os/dir_access.h" - /** @author Juan Linietsky <reduzio@gmail.com> */ + class DirAccessUnix : public DirAccess { DIR *dir_stream; diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index ca16c6fcae..3b97b95f7c 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -33,7 +33,8 @@ #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) #include "core/os/os.h" -#include "print_string.h" +#include "core/print_string.h" + #include <sys/stat.h> #include <sys/types.h> diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 88bb39fbd1..d4a4f8230c 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -31,8 +31,9 @@ #ifndef FILE_ACCESS_UNIX_H #define FILE_ACCESS_UNIX_H -#include "os/file_access.h" -#include "os/memory.h" +#include "core/os/file_access.h" +#include "core/os/memory.h" + #include <stdio.h> #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index d3d1ccfa85..83535045b1 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.h @@ -31,7 +31,7 @@ #ifndef IP_UNIX_H #define IP_UNIX_H -#include "io/ip.h" +#include "core/io/ip.h" #if defined(UNIX_ENABLED) || defined(WINDOWS_ENABLED) diff --git a/drivers/unix/mutex_posix.cpp b/drivers/unix/mutex_posix.cpp index 1f13720f1e..e0004c5730 100644 --- a/drivers/unix/mutex_posix.cpp +++ b/drivers/unix/mutex_posix.cpp @@ -29,7 +29,8 @@ /*************************************************************************/ #include "mutex_posix.h" -#include "os/memory.h" + +#include "core/os/memory.h" #if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED) diff --git a/drivers/unix/mutex_posix.h b/drivers/unix/mutex_posix.h index a4de1603f3..80d85eee61 100644 --- a/drivers/unix/mutex_posix.h +++ b/drivers/unix/mutex_posix.h @@ -33,7 +33,8 @@ #if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED) -#include "os/mutex.h" +#include "core/os/mutex.h" + #include <pthread.h> class MutexPosix : public Mutex { diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp new file mode 100644 index 0000000000..f981be66ce --- /dev/null +++ b/drivers/unix/net_socket_posix.cpp @@ -0,0 +1,617 @@ +/*************************************************************************/ +/* net_socket_posix.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 "net_socket_posix.h" + +#if defined(UNIX_ENABLED) + +#include <errno.h> +#include <netdb.h> +#include <poll.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> +#include <sys/types.h> +#include <unistd.h> +#ifndef NO_FCNTL +#include <fcntl.h> +#else +#include <sys/ioctl.h> +#endif +#include <netinet/in.h> + +#include <sys/socket.h> +#ifdef JAVASCRIPT_ENABLED +#include <arpa/inet.h> +#endif + +#include <netinet/tcp.h> + +#if defined(__APPLE__) +#define MSG_NOSIGNAL SO_NOSIGPIPE +#endif + +// Some custom defines to minimize ifdefs +#define SOCK_EMPTY -1 +#define SOCK_BUF(x) x +#define SOCK_CBUF(x) x +#define SOCK_IOCTL ioctl +#define SOCK_CLOSE ::close + +/* Windows */ +#elif defined(WINDOWS_ENABLED) +#include <winsock2.h> +#include <ws2tcpip.h> + +#include <mswsock.h> +// Some custom defines to minimize ifdefs +#define SOCK_EMPTY INVALID_SOCKET +#define SOCK_BUF(x) (char *)(x) +#define SOCK_CBUF(x) (const char *)(x) +#define SOCK_IOCTL ioctlsocket +#define SOCK_CLOSE closesocket + +// Windows doesn't have this flag +#ifndef MSG_NOSIGNAL +#define MSG_NOSIGNAL 0 +#endif +// Workaround missing flag in MinGW +#if defined(__MINGW32__) && !defined(SIO_UDP_NETRESET) +#define SIO_UDP_NETRESET _WSAIOW(IOC_VENDOR, 15) +#endif + +#endif + +size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) { + + memset(p_addr, 0, sizeof(struct sockaddr_storage)); + if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket + + // IPv6 only socket with IPv4 address + ERR_FAIL_COND_V(!p_ip.is_wildcard() && p_ip_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0); + + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; + addr6->sin6_family = AF_INET6; + addr6->sin6_port = htons(p_port); + if (p_ip.is_valid()) { + copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16); + } else { + addr6->sin6_addr = in6addr_any; + } + return sizeof(sockaddr_in6); + } else { // IPv4 socket + + // IPv4 socket with IPv6 address + ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0); + + struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; + addr4->sin_family = AF_INET; + addr4->sin_port = htons(p_port); // short, network byte order + + if (p_ip.is_valid()) { + copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4); + } else { + addr4->sin_addr.s_addr = INADDR_ANY; + } + + copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 4); + return sizeof(sockaddr_in); + } +} + +void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) { + + if (p_addr->ss_family == AF_INET) { + + struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; + r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); + + r_port = ntohs(addr4->sin_port); + + } else if (p_addr->ss_family == AF_INET6) { + + struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; + r_ip.set_ipv6(addr6->sin6_addr.s6_addr); + + r_port = ntohs(addr6->sin6_port); + }; +} + +NetSocket *NetSocketPosix::_create_func() { + return memnew(NetSocketPosix); +} + +void NetSocketPosix::make_default() { +#if defined(WINDOWS_ENABLED) + if (_create == NULL) { + WSADATA data; + WSAStartup(MAKEWORD(2, 2), &data); + } +#endif + _create = _create_func; +} + +void NetSocketPosix::cleanup() { +#if defined(WINDOWS_ENABLED) + if (_create != NULL) { + WSACleanup(); + } + _create = NULL; +#endif +} + +NetSocketPosix::NetSocketPosix() { + _sock = SOCK_EMPTY; + _ip_type = IP::TYPE_NONE; + _is_stream = false; +} + +NetSocketPosix::~NetSocketPosix() { + close(); +} + +NetSocketPosix::NetError NetSocketPosix::_get_socket_error() { +#if defined(WINDOWS_ENABLED) + int err = WSAGetLastError(); + + if (err == WSAEISCONN) + return ERR_NET_IS_CONNECTED; + if (err == WSAEINPROGRESS || err == WSAEALREADY) + return ERR_NET_IN_PROGRESS; + if (err == WSAEWOULDBLOCK) + return ERR_NET_WOULD_BLOCK; + ERR_PRINTS("Socket error: " + itos(err)); + return ERR_NET_OTHER; +#else + if (errno == EISCONN) + return ERR_NET_IS_CONNECTED; + if (errno == EINPROGRESS || errno == EALREADY) + return ERR_NET_IN_PROGRESS; + if (errno == EAGAIN || errno == EWOULDBLOCK) + return ERR_NET_WOULD_BLOCK; + ERR_PRINTS("Socket error: " + itos(errno)); + return ERR_NET_OTHER; +#endif +} + +bool NetSocketPosix::_can_use_ip(const IP_Address p_ip, const bool p_for_bind) const { + + if (p_for_bind && !(p_ip.is_valid() || p_ip.is_wildcard())) { + return false; + } else if (!p_for_bind && !p_ip.is_valid()) { + return false; + } + // Check if socket support this IP type. + IP::Type type = p_ip.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; + if (_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type) { + return false; + } + return true; +} + +void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) { + _sock = p_sock; + _ip_type = p_ip_type; + _is_stream = p_is_stream; +} + +Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { + ERR_FAIL_COND_V(is_open(), ERR_ALREADY_IN_USE); + ERR_FAIL_COND_V(ip_type > IP::TYPE_ANY || ip_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER); + +#if defined(__OpenBSD__) + // OpenBSD does not support dual stacking, fallback to IPv4 only. + if (ip_type == IP::TYPE_ANY) + ip_type = IP::TYPE_IPV4; +#endif + + int family = ip_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6; + int protocol = p_sock_type == TYPE_TCP ? IPPROTO_TCP : IPPROTO_UDP; + int type = p_sock_type == TYPE_TCP ? SOCK_STREAM : SOCK_DGRAM; + _sock = socket(family, type, protocol); + + if (_sock == SOCK_EMPTY && ip_type == IP::TYPE_ANY) { + // Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket + // in place of a dual stack one, and further calls to _set_sock_addr will work as expected. + ip_type = IP::TYPE_IPV4; + family = AF_INET; + _sock = socket(family, type, protocol); + } + + ERR_FAIL_COND_V(_sock == SOCK_EMPTY, FAILED); + _ip_type = ip_type; + + if (family == AF_INET6) { + // Select IPv4 over IPv6 mapping + set_ipv6_only_enabled(ip_type != IP::TYPE_ANY); + } + + if (protocol == IPPROTO_UDP && ip_type != IP::TYPE_IPV6) { + // Enable broadcasting for UDP sockets if it's not IPv6 only (IPv6 has no broadcast option). + set_broadcasting_enabled(true); + } + + _is_stream = p_sock_type == TYPE_TCP; + +#if defined(WINDOWS_ENABLED) + if (!_is_stream) { + // Disable windows feature/bug reporting WSAECONNRESET/WSAENETRESET when + // recv/recvfrom and an ICMP reply was received from a previous send/sendto. + unsigned long disable = 0; + if (ioctlsocket(_sock, SIO_UDP_CONNRESET, &disable) == SOCKET_ERROR) { + print_verbose("Unable to turn off UDP WSAECONNRESET behaviour on Windows"); + } + if (ioctlsocket(_sock, SIO_UDP_NETRESET, &disable) == SOCKET_ERROR) { + // This feature seems not to be supported on wine. + print_verbose("Unable to turn off UDP WSAENETRESET behaviour on Windows"); + } + } +#endif + return OK; +} + +void NetSocketPosix::close() { + + if (_sock != SOCK_EMPTY) + SOCK_CLOSE(_sock); + + _sock = SOCK_EMPTY; + _ip_type = IP::TYPE_NONE; + _is_stream = false; +} + +Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) { + + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + ERR_FAIL_COND_V(!_can_use_ip(p_addr, true), ERR_INVALID_PARAMETER); + + sockaddr_storage addr; + size_t addr_size = _set_addr_storage(&addr, p_addr, p_port, _ip_type); + + if (::bind(_sock, (struct sockaddr *)&addr, addr_size) == SOCK_EMPTY) { + close(); + ERR_FAIL_V(ERR_UNAVAILABLE); + } + + return OK; +} + +Error NetSocketPosix::listen(int p_max_pending) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + if (::listen(_sock, p_max_pending) == SOCK_EMPTY) { + + close(); + ERR_FAIL_V(FAILED); + }; + + return OK; +} + +Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) { + + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + ERR_FAIL_COND_V(!_can_use_ip(p_host, false), ERR_INVALID_PARAMETER); + + struct sockaddr_storage addr; + size_t addr_size = _set_addr_storage(&addr, p_host, p_port, _ip_type); + + if (::connect(_sock, (struct sockaddr *)&addr, addr_size) == SOCK_EMPTY) { + + NetError err = _get_socket_error(); + + switch (err) { + // We are already connected + case ERR_NET_IS_CONNECTED: + return OK; + // Still waiting to connect, try again in a while + case ERR_NET_WOULD_BLOCK: + case ERR_NET_IN_PROGRESS: + return ERR_BUSY; + default: + ERR_PRINT("Connection to remote host failed!"); + close(); + return FAILED; + } + } + + return OK; +} + +Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { + + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + +#if defined(WINDOWS_ENABLED) + bool ready = false; + fd_set rd, wr, ex; + fd_set *rdp = NULL; + fd_set *wrp = NULL; + FD_ZERO(&rd); + FD_ZERO(&wr); + FD_ZERO(&ex); + FD_SET(_sock, &ex); + struct timeval timeout = { p_timeout, 0 }; + // For blocking operation, pass NULL timeout pointer to select. + struct timeval *tp = NULL; + if (p_timeout >= 0) { + // If timeout is non-negative, we want to specify the timeout instead. + tp = &timeout; + } + + switch (p_type) { + case POLL_TYPE_IN: + FD_SET(_sock, &rd); + rdp = &rd; + break; + case POLL_TYPE_OUT: + FD_SET(_sock, &wr); + wrp = ≀ + break; + case POLL_TYPE_IN_OUT: + FD_SET(_sock, &rd); + FD_SET(_sock, &wr); + rdp = &rd; + wrp = ≀ + } + int ret = select(1, rdp, wrp, &ex, tp); + + ERR_FAIL_COND_V(ret == SOCKET_ERROR, FAILED); + + if (ret == 0) + return ERR_BUSY; + + ERR_FAIL_COND_V(FD_ISSET(_sock, &ex), FAILED); + + if (rdp && FD_ISSET(_sock, rdp)) + ready = true; + if (wrp && FD_ISSET(_sock, wrp)) + ready = true; + + return ready ? OK : ERR_BUSY; +#else + struct pollfd pfd; + pfd.fd = _sock; + pfd.events = POLLIN; + pfd.revents = 0; + + switch (p_type) { + case POLL_TYPE_IN: + pfd.events = POLLIN; + break; + case POLL_TYPE_OUT: + pfd.events = POLLOUT; + break; + case POLL_TYPE_IN_OUT: + pfd.events = POLLOUT || POLLIN; + } + + int ret = ::poll(&pfd, 1, p_timeout); + + ERR_FAIL_COND_V(ret < 0, FAILED); + ERR_FAIL_COND_V(pfd.revents & POLLERR, FAILED); + + if (ret == 0) + return ERR_BUSY; + + return OK; +#endif +} + +Error NetSocketPosix::recv(uint8_t *p_buffer, int p_len, int &r_read) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + r_read = ::recv(_sock, SOCK_BUF(p_buffer), p_len, 0); + + if (r_read < 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_WOULD_BLOCK) + return ERR_BUSY; + + return FAILED; + } + + return OK; +} + +Error NetSocketPosix::recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + struct sockaddr_storage from; + socklen_t len = sizeof(struct sockaddr_storage); + memset(&from, 0, len); + + r_read = ::recvfrom(_sock, SOCK_BUF(p_buffer), p_len, 0, (struct sockaddr *)&from, &len); + + if (r_read < 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_WOULD_BLOCK) + return ERR_BUSY; + + return FAILED; + } + + if (from.ss_family == AF_INET) { + struct sockaddr_in *sin_from = (struct sockaddr_in *)&from; + r_ip.set_ipv4((uint8_t *)&sin_from->sin_addr); + r_port = ntohs(sin_from->sin_port); + } else if (from.ss_family == AF_INET6) { + struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from; + r_ip.set_ipv6((uint8_t *)&s6_from->sin6_addr); + r_port = ntohs(s6_from->sin6_port); + } else { + // Unsupported socket family, should never happen. + ERR_FAIL_V(FAILED); + } + + return OK; +} + +Error NetSocketPosix::send(const uint8_t *p_buffer, int p_len, int &r_sent) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + int flags = 0; + if (_is_stream) + flags = MSG_NOSIGNAL; + r_sent = ::send(_sock, SOCK_CBUF(p_buffer), p_len, flags); + + if (r_sent < 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_WOULD_BLOCK) + return ERR_BUSY; + + return FAILED; + } + + return OK; +} + +Error NetSocketPosix::sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port) { + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + + struct sockaddr_storage addr; + size_t addr_size = _set_addr_storage(&addr, p_ip, p_port, _ip_type); + r_sent = ::sendto(_sock, SOCK_CBUF(p_buffer), p_len, 0, (struct sockaddr *)&addr, addr_size); + + if (r_sent < 0) { + NetError err = _get_socket_error(); + if (err == ERR_NET_WOULD_BLOCK) + return ERR_BUSY; + + return FAILED; + } + + return OK; +} + +void NetSocketPosix::set_broadcasting_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + // IPv6 has no broadcast support. + ERR_FAIL_COND(_ip_type == IP::TYPE_IPV6); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, SOL_SOCKET, SO_BROADCAST, SOCK_CBUF(&par), sizeof(int)) != 0) { + WARN_PRINT("Unable to change broadcast setting"); + } +} + +void NetSocketPosix::set_blocking_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + + int ret = 0; +#if defined(WINDOWS_ENABLED) || defined(NO_FCNTL) + unsigned long par = p_enabled ? 0 : 1; + ret = SOCK_IOCTL(_sock, FIONBIO, &par); +#else + int opts = fcntl(_sock, F_GETFL); + if (p_enabled) + ret = fcntl(_sock, F_SETFL, opts & ~O_NONBLOCK); + else + ret = fcntl(_sock, F_SETFL, opts | O_NONBLOCK); +#endif + + if (ret != 0) + WARN_PRINT("Unable to change non-block mode"); +} + +void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + // This option is only avaiable in IPv6 sockets. + ERR_FAIL_COND(_ip_type == IP::TYPE_IPV4); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, IPPROTO_IPV6, IPV6_V6ONLY, SOCK_CBUF(&par), sizeof(int)) != 0) { + WARN_PRINT("Unable to change IPv4 address mapping over IPv6 option"); + } +} + +void NetSocketPosix::set_tcp_no_delay_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + ERR_FAIL_COND(!_is_stream); // Not TCP + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, SOCK_CBUF(&par), sizeof(int)) < 0) { + ERR_PRINT("Unable to set TCP no delay option"); + } +} + +void NetSocketPosix::set_reuse_address_enabled(bool p_enabled) { + ERR_FAIL_COND(!is_open()); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, SOL_SOCKET, SO_REUSEADDR, SOCK_CBUF(&par), sizeof(int)) < 0) { + WARN_PRINT("Unable to set socket REUSEADDR option!"); + } +} + +void NetSocketPosix::set_reuse_port_enabled(bool p_enabled) { +// Windows does not have this option, as it is always ON when setting REUSEADDR. +#ifndef WINDOWS_ENABLED + ERR_FAIL_COND(!is_open()); + + int par = p_enabled ? 1 : 0; + if (setsockopt(_sock, SOL_SOCKET, SO_REUSEPORT, SOCK_CBUF(&par), sizeof(int)) < 0) { + WARN_PRINT("Unable to set socket REUSEPORT option!"); + } +#endif +} + +bool NetSocketPosix::is_open() const { + return _sock != SOCK_EMPTY; +} + +int NetSocketPosix::get_available_bytes() const { + + ERR_FAIL_COND_V(_sock == SOCK_EMPTY, -1); + + unsigned long len; + int ret = SOCK_IOCTL(_sock, FIONREAD, &len); + ERR_FAIL_COND_V(ret == -1, 0); + return len; +} + +Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { + + Ref<NetSocket> out; + ERR_FAIL_COND_V(!is_open(), out); + + struct sockaddr_storage their_addr; + socklen_t size = sizeof(their_addr); + SOCKET_TYPE fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size); + ERR_FAIL_COND_V(fd == SOCK_EMPTY, out); + + _set_ip_port(&their_addr, r_ip, r_port); + + NetSocketPosix *ns = memnew(NetSocketPosix); + ns->_set_socket(fd, _ip_type, _is_stream); + ns->set_blocking_enabled(false); + return Ref<NetSocket>(ns); +} diff --git a/drivers/windows/stream_peer_tcp_winsock.h b/drivers/unix/net_socket_posix.h index a0177d374e..010f2ea6e0 100644 --- a/drivers/windows/stream_peer_tcp_winsock.h +++ b/drivers/unix/net_socket_posix.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* stream_peer_tcp_winsock.h */ +/* net_socket_posix.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,65 +28,74 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#ifdef WINDOWS_ENABLED +#ifndef NET_SOCKET_UNIX_H +#define NET_SOCKET_UNIX_H -#ifndef STREAM_PEER_TCP_WINSOCK_H -#define STREAM_PEER_TCP_WINSOCK_H +#include "core/io/net_socket.h" -#include "error_list.h" +#if defined(WINDOWS_ENABLED) +#include <winsock2.h> +#include <ws2tcpip.h> +#define SOCKET_TYPE SOCKET -#include "core/io/ip_address.h" -#include "core/io/stream_peer_tcp.h" +#else +#include <sys/socket.h> +#define SOCKET_TYPE int -class StreamPeerTCPWinsock : public StreamPeerTCP { - -protected: - mutable Status status; - IP::Type sock_type; +#endif - int sockfd; +class NetSocketPosix : public NetSocket { - Error _block(int p_sockfd, bool p_read, bool p_write) const; +private: + SOCKET_TYPE _sock; + IP::Type _ip_type; + bool _is_stream; - Error _poll_connection() const; + enum NetError { + ERR_NET_WOULD_BLOCK, + ERR_NET_IS_CONNECTED, + ERR_NET_IN_PROGRESS, + ERR_NET_OTHER + }; - IP_Address peer_host; - int peer_port; + NetError _get_socket_error(); + void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream); - Error write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block); - Error read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block); +protected: + static NetSocket *_create_func(); - static StreamPeerTCP *_create(); + bool _can_use_ip(const IP_Address p_ip, const bool p_for_bind) const; public: - virtual Error connect_to_host(const IP_Address &p_host, uint16_t p_port); - - virtual Error put_data(const uint8_t *p_data, int p_bytes); - virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent); - - virtual Error get_data(uint8_t *p_buffer, int p_bytes); - virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received); - - virtual int get_available_bytes() const; - - void set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type); - - virtual IP_Address get_connected_host() const; - virtual uint16_t get_connected_port() const; - - virtual bool is_connected_to_host() const; - virtual Status get_status() const; - virtual void disconnect_from_host(); - static void make_default(); static void cleanup(); + static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port); + static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type); + + virtual Error open(Type p_sock_type, IP::Type &ip_type); + virtual void close(); + virtual Error bind(IP_Address p_addr, uint16_t p_port); + virtual Error listen(int p_max_pending); + virtual Error connect_to_host(IP_Address p_addr, uint16_t p_port); + virtual Error poll(PollType p_type, int timeout) const; + virtual Error recv(uint8_t *p_buffer, int p_len, int &r_read); + virtual Error recvfrom(uint8_t *p_buffer, int p_len, int &r_read, IP_Address &r_ip, uint16_t &r_port); + virtual Error send(const uint8_t *p_buffer, int p_len, int &r_sent); + virtual Error sendto(const uint8_t *p_buffer, int p_len, int &r_sent, IP_Address p_ip, uint16_t p_port); + virtual Ref<NetSocket> accept(IP_Address &r_ip, uint16_t &r_port); + + virtual bool is_open() const; + virtual int get_available_bytes() const; - virtual void set_no_delay(bool p_enabled); + virtual void set_broadcasting_enabled(bool p_enabled); + virtual void set_blocking_enabled(bool p_enabled); + virtual void set_ipv6_only_enabled(bool p_enabled); + virtual void set_tcp_no_delay_enabled(bool p_enabled); + virtual void set_reuse_address_enabled(bool p_enabled); + virtual void set_reuse_port_enabled(bool p_enabled); - StreamPeerTCPWinsock(); - ~StreamPeerTCPWinsock(); + NetSocketPosix(); + ~NetSocketPosix(); }; -#endif // STREAM_PEER_TCP_WINSOCK_H - #endif diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 05dfd69f58..279274734f 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -32,30 +32,27 @@ #ifdef UNIX_ENABLED -#include "servers/visual_server.h" - #include "core/os/thread_dummy.h" -#include "mutex_posix.h" -#include "rw_lock_posix.h" -#include "semaphore_posix.h" -#include "thread_posix.h" - -//#include "core/io/file_access_buffered_fa.h" -#include "dir_access_unix.h" -#include "file_access_unix.h" -#include "packet_peer_udp_posix.h" -#include "stream_peer_tcp_posix.h" -#include "tcp_server_posix.h" +#include "core/project_settings.h" +#include "drivers/unix/dir_access_unix.h" +#include "drivers/unix/file_access_unix.h" +#include "drivers/unix/mutex_posix.h" +#include "drivers/unix/net_socket_posix.h" +#include "drivers/unix/rw_lock_posix.h" +#include "drivers/unix/semaphore_posix.h" +#include "drivers/unix/thread_posix.h" +#include "servers/visual_server.h" #ifdef __APPLE__ #include <mach-o/dyld.h> +#include <mach/mach_time.h> #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) #include <sys/param.h> #include <sys/sysctl.h> #endif -#include "project_settings.h" + #include <assert.h> #include <dlfcn.h> #include <errno.h> @@ -68,6 +65,32 @@ #include <sys/wait.h> #include <unistd.h> +/// Clock Setup function (used by get_ticks_usec) +static uint64_t _clock_start = 0; +#if defined(__APPLE__) +static double _clock_scale = 0; +static void _setup_clock() { + mach_timebase_info_data_t info; + kern_return_t ret = mach_timebase_info(&info); + ERR_EXPLAIN("OS CLOCK IS NOT WORKING!"); + ERR_FAIL_COND(ret != 0); + _clock_scale = ((double)info.numer / (double)info.denom) / 1000.0; + _clock_start = mach_absolute_time() * _clock_scale; +} +#else +#if defined(CLOCK_MONOTONIC_RAW) && !defined(JAVASCRIPT_ENABLED) // This is a better clock on Linux. +#define GODOT_CLOCK CLOCK_MONOTONIC_RAW +#else +#define GODOT_CLOCK CLOCK_MONOTONIC +#endif +static void _setup_clock() { + struct timespec tv_now = { 0, 0 }; + ERR_EXPLAIN("OS CLOCK IS NOT WORKING!"); + ERR_FAIL_COND(clock_gettime(GODOT_CLOCK, &tv_now) != 0); + _clock_start = ((uint64_t)tv_now.tv_nsec / 1000L) + (uint64_t)tv_now.tv_sec * 1000000L; +} +#endif + void OS_Unix::debug_break() { assert(false); @@ -126,14 +149,11 @@ void OS_Unix::initialize_core() { DirAccess::make_default<DirAccessUnix>(DirAccess::ACCESS_FILESYSTEM); #ifndef NO_NETWORK - TCPServerPosix::make_default(); - StreamPeerTCPPosix::make_default(); - PacketPeerUDPPosix::make_default(); + NetSocketPosix::make_default(); IP_Unix::make_default(); #endif - ticks_start = 0; - ticks_start = get_ticks_usec(); + _setup_clock(); struct sigaction sa; sa.sa_handler = &handle_sigchld; @@ -145,6 +165,8 @@ void OS_Unix::initialize_core() { } void OS_Unix::finalize_core() { + + NetSocketPosix::cleanup(); } void OS_Unix::alert(const String &p_alert, const String &p_title) { @@ -250,17 +272,27 @@ void OS_Unix::delay_usec(uint32_t p_usec) const { } uint64_t OS_Unix::get_ticks_usec() const { - struct timeval tv_now; - gettimeofday(&tv_now, NULL); - - uint64_t longtime = (uint64_t)tv_now.tv_usec + (uint64_t)tv_now.tv_sec * 1000000L; - longtime -= ticks_start; +#if defined(__APPLE__) + uint64_t longtime = mach_absolute_time() * _clock_scale; +#else + // Unchecked return. Static analyzers might complain. + // If _setup_clock() succeded, we assume clock_gettime() works. + struct timespec tv_now = { 0, 0 }; + clock_gettime(GODOT_CLOCK, &tv_now); + uint64_t longtime = ((uint64_t)tv_now.tv_nsec / 1000L) + (uint64_t)tv_now.tv_sec * 1000000L; +#endif + longtime -= _clock_start; return longtime; } Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else if (p_blocking && r_pipe) { String argss; @@ -327,6 +359,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo } return OK; +#endif } Error OS_Unix::kill(const ProcessID &p_pid) { @@ -460,9 +493,11 @@ String OS_Unix::get_executable_path() const { //fix for running from a symlink char buf[256]; memset(buf, 0, 256); - readlink("/proc/self/exe", buf, sizeof(buf)); + ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf)); String b; - b.parse_utf8(buf); + if (len > 0) { + b.parse_utf8(buf, len); + } if (b == "") { WARN_PRINT("Couldn't get executable path from /proc/self/exe, using argv[0]"); return OS::get_executable_path(); diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 95b74d23ff..b702454603 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -37,13 +37,11 @@ #ifdef UNIX_ENABLED +#include "core/os/os.h" #include "drivers/unix/ip_unix.h" -#include "os/os.h" class OS_Unix : public OS { - uint64_t ticks_start; - protected: // UNIX only handles the core functions. // inheriting platforms under unix (eg. X11) should handle the rest diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp deleted file mode 100644 index 1380c1d88b..0000000000 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ /dev/null @@ -1,317 +0,0 @@ -/*************************************************************************/ -/* packet_peer_udp_posix.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 "packet_peer_udp_posix.h" - -#ifdef UNIX_ENABLED - -#include <errno.h> -#include <netdb.h> -#include <sys/socket.h> -#include <sys/types.h> -#include <unistd.h> - -#include <netinet/in.h> -#include <stdio.h> - -#ifndef NO_FCNTL -#ifdef __HAIKU__ -#include <fcntl.h> -#else -#include <sys/fcntl.h> -#endif -#else -#include <sys/ioctl.h> -#endif - -#ifdef JAVASCRIPT_ENABLED -#include <arpa/inet.h> -#endif - -#include "drivers/unix/socket_helpers.h" - -int PacketPeerUDPPosix::get_available_packet_count() const { - - Error err = const_cast<PacketPeerUDPPosix *>(this)->_poll(false); - if (err != OK) - return 0; - - return queue_count; -} - -Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - - Error err = const_cast<PacketPeerUDPPosix *>(this)->_poll(false); - if (err != OK) - return err; - if (queue_count == 0) - return ERR_UNAVAILABLE; - - uint32_t size = 0; - uint8_t type = IP::TYPE_NONE; - rb.read(&type, 1, true); - if (type == IP::TYPE_IPV4) { - uint8_t ip[4]; - rb.read(ip, 4, true); - packet_ip.set_ipv4(ip); - } else { - uint8_t ipv6[16]; - rb.read(ipv6, 16, true); - packet_ip.set_ipv6(ipv6); - }; - rb.read((uint8_t *)&packet_port, 4, true); - rb.read((uint8_t *)&size, 4, true); - rb.read(packet_buffer, size, true); - --queue_count; - *r_buffer = packet_buffer; - r_buffer_size = size; - return OK; -} -Error PacketPeerUDPPosix::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - - ERR_FAIL_COND_V(!peer_addr.is_valid(), ERR_UNCONFIGURED); - - if (sock_type == IP::TYPE_NONE) - sock_type = peer_addr.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - int sock = _get_socket(); - ERR_FAIL_COND_V(sock == -1, FAILED); - struct sockaddr_storage addr; - size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port, sock_type); - - errno = 0; - int err; - - _set_sock_blocking(blocking); - - while ((err = sendto(sock, p_buffer, p_buffer_size, 0, (struct sockaddr *)&addr, addr_size)) != p_buffer_size) { - - if (errno != EAGAIN) { - return FAILED; - } else if (!blocking) { - return ERR_UNAVAILABLE; - } - } - - return OK; -} - -int PacketPeerUDPPosix::get_max_packet_size() const { - - return 512; // uhm maybe not -} - -Error PacketPeerUDPPosix::listen(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) { - - ERR_FAIL_COND_V(sockfd != -1, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - -#ifdef __OpenBSD__ - sock_type = IP::TYPE_IPV4; // OpenBSD does not support dual stacking, fallback to IPv4 only. -#else - sock_type = IP::TYPE_ANY; -#endif - - if (p_bind_address.is_valid()) - sock_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - int sock = _get_socket(); - - if (sock == -1) - return ERR_CANT_CREATE; - - sockaddr_storage addr = { 0 }; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, sock_type, IP_Address()); - - if (bind(sock, (struct sockaddr *)&addr, addr_size) == -1) { - close(); - return ERR_UNAVAILABLE; - } - rb.resize(nearest_shift(p_recv_buffer_size)); - return OK; -} - -void PacketPeerUDPPosix::close() { - - if (sockfd != -1) - ::close(sockfd); - sockfd = -1; - sock_type = IP::TYPE_NONE; - rb.resize(16); - queue_count = 0; -} - -Error PacketPeerUDPPosix::wait() { - - return _poll(true); -} - -Error PacketPeerUDPPosix::_poll(bool p_block) { - - if (sockfd == -1) { - return FAILED; - } - - _set_sock_blocking(p_block); - - struct sockaddr_storage from = { 0 }; - socklen_t len = sizeof(struct sockaddr_storage); - int ret; - while ((ret = recvfrom(sockfd, recv_buffer, MIN((int)sizeof(recv_buffer), MAX(rb.space_left() - 24, 0)), 0, (struct sockaddr *)&from, &len)) > 0) { - - uint32_t port = 0; - - if (from.ss_family == AF_INET) { - uint8_t type = (uint8_t)IP::TYPE_IPV4; - rb.write(&type, 1); - struct sockaddr_in *sin_from = (struct sockaddr_in *)&from; - rb.write((uint8_t *)&sin_from->sin_addr, 4); - port = ntohs(sin_from->sin_port); - - } else if (from.ss_family == AF_INET6) { - - uint8_t type = (uint8_t)IP::TYPE_IPV6; - rb.write(&type, 1); - - struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from; - rb.write((uint8_t *)&s6_from->sin6_addr, 16); - - port = ntohs(s6_from->sin6_port); - - } else { - // WARN_PRINT("Ignoring packet with unknown address family"); - uint8_t type = (uint8_t)IP::TYPE_NONE; - rb.write(&type, 1); - }; - - rb.write((uint8_t *)&port, 4); - rb.write((uint8_t *)&ret, 4); - rb.write(recv_buffer, ret); - - len = sizeof(struct sockaddr_storage); - ++queue_count; - if (p_block) - break; - }; - - // TODO: Should ECONNRESET be handled here? - if (ret == 0 || (ret == -1 && errno != EAGAIN)) { - close(); - return FAILED; - }; - - return OK; -} -bool PacketPeerUDPPosix::is_listening() const { - - return sockfd != -1; -} - -IP_Address PacketPeerUDPPosix::get_packet_address() const { - - return packet_ip; -} - -int PacketPeerUDPPosix::get_packet_port() const { - - return packet_port; -} - -int PacketPeerUDPPosix::_get_socket() { - - ERR_FAIL_COND_V(sock_type == IP::TYPE_NONE, -1); - - if (sockfd != -1) - return sockfd; - - sockfd = _socket_create(sock_type, SOCK_DGRAM, IPPROTO_UDP); - - if (sockfd != -1) - _set_sock_blocking(false); - - return sockfd; -} - -void PacketPeerUDPPosix::_set_sock_blocking(bool p_blocking) { - - if (sock_blocking == p_blocking) - return; - - sock_blocking = p_blocking; - -#ifndef NO_FCNTL - int opts = fcntl(sockfd, F_GETFL); - int ret = 0; - if (sock_blocking) - ret = fcntl(sockfd, F_SETFL, opts & ~O_NONBLOCK); - else - ret = fcntl(sockfd, F_SETFL, opts | O_NONBLOCK); - if (ret == -1) - perror("setting non-block mode"); -#else - int bval = sock_blocking ? 0 : 1; - if (ioctl(sockfd, FIONBIO, &bval) == -1) - perror("setting non-block mode"); -#endif -} - -void PacketPeerUDPPosix::set_dest_address(const IP_Address &p_address, int p_port) { - - peer_addr = p_address; - peer_port = p_port; -} - -PacketPeerUDP *PacketPeerUDPPosix::_create() { - - return memnew(PacketPeerUDPPosix); -}; - -void PacketPeerUDPPosix::make_default() { - - PacketPeerUDP::_create = PacketPeerUDPPosix::_create; -}; - -PacketPeerUDPPosix::PacketPeerUDPPosix() { - - blocking = true; - sock_blocking = true; - sockfd = -1; - packet_port = 0; - queue_count = 0; - peer_port = 0; - sock_type = IP::TYPE_NONE; - rb.resize(16); -} - -PacketPeerUDPPosix::~PacketPeerUDPPosix() { - - close(); -} -#endif diff --git a/drivers/unix/packet_peer_udp_posix.h b/drivers/unix/packet_peer_udp_posix.h deleted file mode 100644 index 7f72a9bfc9..0000000000 --- a/drivers/unix/packet_peer_udp_posix.h +++ /dev/null @@ -1,88 +0,0 @@ -/*************************************************************************/ -/* packet_peer_udp_posix.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 PACKET_PEER_UDP_POSIX_H -#define PACKET_PEER_UDP_POSIX_H - -#ifdef UNIX_ENABLED - -#include "io/packet_peer_udp.h" -#include "ring_buffer.h" - -class PacketPeerUDPPosix : public PacketPeerUDP { - - enum { - PACKET_BUFFER_SIZE = 65536 - }; - - RingBuffer<uint8_t> rb; - uint8_t recv_buffer[PACKET_BUFFER_SIZE]; - uint8_t packet_buffer[PACKET_BUFFER_SIZE]; - IP_Address packet_ip; - int packet_port; - int queue_count; - int sockfd; - bool sock_blocking; - IP::Type sock_type; - - IP_Address peer_addr; - int peer_port; - - _FORCE_INLINE_ int _get_socket(); - - static PacketPeerUDP *_create(); - void _set_sock_blocking(bool p_blocking); - virtual Error _poll(bool p_block); - -public: - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - - virtual int get_max_packet_size() const; - - virtual Error listen(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536); - virtual void close(); - virtual Error wait(); - virtual bool is_listening() const; - - virtual IP_Address get_packet_address() const; - virtual int get_packet_port() const; - - virtual void set_dest_address(const IP_Address &p_address, int p_port); - - static void make_default(); - - PacketPeerUDPPosix(); - ~PacketPeerUDPPosix(); -}; - -#endif // PACKET_PEER_UDP_POSIX_H -#endif diff --git a/drivers/unix/rw_lock_posix.cpp b/drivers/unix/rw_lock_posix.cpp index 4df965cabb..27b19c30d5 100644 --- a/drivers/unix/rw_lock_posix.cpp +++ b/drivers/unix/rw_lock_posix.cpp @@ -32,8 +32,8 @@ #include "rw_lock_posix.h" -#include "error_macros.h" -#include "os/memory.h" +#include "core/error_macros.h" +#include "core/os/memory.h" #include <stdio.h> void RWLockPosix::read_lock() { diff --git a/drivers/unix/rw_lock_posix.h b/drivers/unix/rw_lock_posix.h index 617b9705da..897b617f98 100644 --- a/drivers/unix/rw_lock_posix.h +++ b/drivers/unix/rw_lock_posix.h @@ -33,7 +33,7 @@ #if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED) -#include "os/rw_lock.h" +#include "core/os/rw_lock.h" #include <pthread.h> class RWLockPosix : public RWLock { diff --git a/drivers/unix/semaphore_posix.cpp b/drivers/unix/semaphore_posix.cpp index 5cabfe4937..26c2aeab28 100644 --- a/drivers/unix/semaphore_posix.cpp +++ b/drivers/unix/semaphore_posix.cpp @@ -32,7 +32,7 @@ #if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED) -#include "os/memory.h" +#include "core/os/memory.h" #include <errno.h> #include <stdio.h> diff --git a/drivers/unix/semaphore_posix.h b/drivers/unix/semaphore_posix.h index 283174bb2e..025b87c0d7 100644 --- a/drivers/unix/semaphore_posix.h +++ b/drivers/unix/semaphore_posix.h @@ -31,7 +31,7 @@ #ifndef SEMAPHORE_POSIX_H #define SEMAPHORE_POSIX_H -#include "os/semaphore.h" +#include "core/os/semaphore.h" #if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED) diff --git a/drivers/unix/socket_helpers.h b/drivers/unix/socket_helpers.h deleted file mode 100644 index 5b42c13eae..0000000000 --- a/drivers/unix/socket_helpers.h +++ /dev/null @@ -1,156 +0,0 @@ -/*************************************************************************/ -/* socket_helpers.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 SOCKET_HELPERS_H -#define SOCKET_HELPERS_H - -#include <string.h> - -#if defined(__MINGW32__) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4) -// Workaround for mingw-w64 < 4.0 -#ifndef IPV6_V6ONLY -#define IPV6_V6ONLY 27 -#endif -#endif - -// helpers for sockaddr -> IP_Address and back, should work for posix and winsock. All implementations should use this - -static size_t _set_sockaddr(struct sockaddr_storage *p_addr, const IP_Address &p_ip, int p_port, IP::Type p_sock_type = IP::TYPE_ANY) { - - memset(p_addr, 0, sizeof(struct sockaddr_storage)); - - ERR_FAIL_COND_V(!p_ip.is_valid(), 0); - - // IPv6 socket - if (p_sock_type == IP::TYPE_IPV6 || p_sock_type == IP::TYPE_ANY) { - - // IPv6 only socket with IPv4 address - ERR_FAIL_COND_V(p_sock_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0); - - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - addr6->sin6_family = AF_INET6; - addr6->sin6_port = htons(p_port); - copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16); - return sizeof(sockaddr_in6); - - } else { // IPv4 socket - - // IPv4 socket with IPv6 address - ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0); - - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - addr4->sin_family = AF_INET; - addr4->sin_port = htons(p_port); // short, network byte order - copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); - return sizeof(sockaddr_in); - }; -}; - -static size_t _set_listen_sockaddr(struct sockaddr_storage *p_addr, int p_port, IP::Type p_sock_type, const IP_Address p_bind_address) { - - memset(p_addr, 0, sizeof(struct sockaddr_storage)); - if (p_sock_type == IP::TYPE_IPV4) { - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - addr4->sin_family = AF_INET; - addr4->sin_port = htons(p_port); - if (p_bind_address.is_valid()) { - copymem(&addr4->sin_addr.s_addr, p_bind_address.get_ipv4(), 4); - } else { - addr4->sin_addr.s_addr = INADDR_ANY; - } - return sizeof(sockaddr_in); - } else { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - - addr6->sin6_family = AF_INET6; - addr6->sin6_port = htons(p_port); - if (p_bind_address.is_valid()) { - copymem(&addr6->sin6_addr.s6_addr, p_bind_address.get_ipv6(), 16); - } else { - addr6->sin6_addr = in6addr_any; - } - return sizeof(sockaddr_in6); - }; -}; - -static int _socket_create(IP::Type &p_type, int type, int protocol) { - - ERR_FAIL_COND_V(p_type > IP::TYPE_ANY || p_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER); - - int family = p_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6; - int sockfd = socket(family, type, protocol); - - if (sockfd == -1 && p_type == IP::TYPE_ANY) { - // Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket - // in place of a dual stack one, and further calls to _set_sock_addr will work as expected. - p_type = IP::TYPE_IPV4; - family = AF_INET; - sockfd = socket(family, type, protocol); - } - - ERR_FAIL_COND_V(sockfd == -1, -1); - - if (family == AF_INET6) { - // Select IPv4 over IPv6 mapping - int opt = p_type != IP::TYPE_ANY; - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&opt, sizeof(opt)) != 0) { - WARN_PRINT("Unable to set/unset IPv4 address mapping over IPv6"); - } - } - if (protocol == IPPROTO_UDP && p_type != IP::TYPE_IPV6) { - // Enable broadcasting for UDP sockets if it's not IPv6 only (IPv6 has no broadcast option). - int broadcast = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)) != 0) { - WARN_PRINT("Error when enabling broadcasting"); - } - } - - return sockfd; -} - -static void _set_ip_addr_port(IP_Address &r_ip, int &r_port, struct sockaddr_storage *p_addr) { - - if (p_addr->ss_family == AF_INET) { - - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); - - r_port = ntohs(addr4->sin_port); - - } else if (p_addr->ss_family == AF_INET6) { - - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - r_ip.set_ipv6(addr6->sin6_addr.s6_addr); - - r_port = ntohs(addr6->sin6_port); - }; -}; - -#endif diff --git a/drivers/unix/stream_peer_tcp_posix.cpp b/drivers/unix/stream_peer_tcp_posix.cpp deleted file mode 100644 index 44b9ef1d7c..0000000000 --- a/drivers/unix/stream_peer_tcp_posix.cpp +++ /dev/null @@ -1,411 +0,0 @@ -/*************************************************************************/ -/* stream_peer_tcp_posix.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. */ -/*************************************************************************/ - -#ifdef UNIX_ENABLED - -#include "stream_peer_tcp_posix.h" - -#include <errno.h> -#include <netdb.h> -#include <poll.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/ioctl.h> -#include <sys/types.h> -#include <unistd.h> -#ifndef NO_FCNTL -#ifdef __HAIKU__ -#include <fcntl.h> -#else -#include <sys/fcntl.h> -#endif -#else -#include <sys/ioctl.h> -#endif -#include <netinet/in.h> - -#include <sys/socket.h> -#ifdef JAVASCRIPT_ENABLED -#include <arpa/inet.h> -#endif - -#include <netinet/tcp.h> - -#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) -#define MSG_NOSIGNAL SO_NOSIGPIPE -#endif - -#include "drivers/unix/socket_helpers.h" - -StreamPeerTCP *StreamPeerTCPPosix::_create() { - - return memnew(StreamPeerTCPPosix); -}; - -void StreamPeerTCPPosix::make_default() { - - StreamPeerTCP::_create = StreamPeerTCPPosix::_create; -}; - -Error StreamPeerTCPPosix::_block(int p_sockfd, bool p_read, bool p_write) const { - - struct pollfd pfd; - pfd.fd = p_sockfd; - pfd.events = 0; - if (p_read) - pfd.events |= POLLIN; - if (p_write) - pfd.events |= POLLOUT; - pfd.revents = 0; - - int ret = poll(&pfd, 1, -1); - return ret < 0 ? FAILED : OK; -}; - -Error StreamPeerTCPPosix::_poll_connection() const { - - ERR_FAIL_COND_V(status != STATUS_CONNECTING || sockfd == -1, FAILED); - - struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port, sock_type); - - if (::connect(sockfd, (struct sockaddr *)&their_addr, addr_size) == -1) { - - if (errno == EISCONN) { - status = STATUS_CONNECTED; - return OK; - }; - - if (errno == EINPROGRESS || errno == EALREADY) { - return OK; - } - - status = STATUS_ERROR; - return ERR_CONNECTION_ERROR; - } else { - - status = STATUS_CONNECTED; - return OK; - }; - - return OK; -}; - -void StreamPeerTCPPosix::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type) { - - sock_type = p_sock_type; - sockfd = p_sockfd; -#ifndef NO_FCNTL - if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#else - int bval = 1; - if (ioctl(sockfd, FIONBIO, &bval) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#endif - status = STATUS_CONNECTING; - - peer_host = p_host; - peer_port = p_port; -}; - -Error StreamPeerTCPPosix::connect_to_host(const IP_Address &p_host, uint16_t p_port) { - - ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER); - - sock_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - sockfd = _socket_create(sock_type, SOCK_STREAM, IPPROTO_TCP); - if (sockfd == -1) { - ERR_PRINT("Socket creation failed!"); - disconnect_from_host(); - //perror("socket"); - return FAILED; - }; - -#ifndef NO_FCNTL - if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#else - int bval = 1; - if (ioctl(sockfd, FIONBIO, &bval) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#endif - - struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port, sock_type); - - errno = 0; - if (::connect(sockfd, (struct sockaddr *)&their_addr, addr_size) == -1 && errno != EINPROGRESS) { - - ERR_PRINT("Connection to remote host failed!"); - disconnect_from_host(); - return FAILED; - }; - - if (errno == EINPROGRESS) { - status = STATUS_CONNECTING; - } else { - status = STATUS_CONNECTED; - }; - - peer_host = p_host; - peer_port = p_port; - - return OK; -}; - -Error StreamPeerTCPPosix::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) { - - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - - if (_poll_connection() != OK) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - r_sent = 0; - return OK; - }; - }; - - int data_to_send = p_bytes; - const uint8_t *offset = p_data; - if (sockfd == -1) return FAILED; - errno = 0; - int total_sent = 0; - - while (data_to_send) { - - int sent_amount = send(sockfd, offset, data_to_send, MSG_NOSIGNAL); - //printf("Sent TCP data of %d bytes, errno %d\n", sent_amount, errno); - - if (sent_amount == -1) { - - if (errno != EAGAIN) { - - perror("Nothing sent"); - disconnect_from_host(); - ERR_PRINT("Server disconnected!\n"); - return FAILED; - }; - - if (!p_block) { - r_sent = total_sent; - return OK; - }; - - _block(sockfd, false, true); - } else { - - data_to_send -= sent_amount; - offset += sent_amount; - total_sent += sent_amount; - }; - } - - r_sent = total_sent; - - return OK; -}; - -Error StreamPeerTCPPosix::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) { - - if (!is_connected_to_host()) { - - return FAILED; - }; - - if (status == STATUS_CONNECTING) { - - if (_poll_connection() != OK) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - r_received = 0; - return OK; - }; - }; - - int to_read = p_bytes; - int total_read = 0; - errno = 0; - - while (to_read) { - - int read = recv(sockfd, p_buffer + total_read, to_read, 0); - - if (read == -1) { - - if (errno != EAGAIN) { - - perror("Nothing read"); - disconnect_from_host(); - ERR_PRINT("Server disconnected!\n"); - return FAILED; - }; - - if (!p_block) { - - r_received = total_read; - return OK; - }; - _block(sockfd, true, false); - - } else if (read == 0) { - - sockfd = -1; - status = STATUS_NONE; - peer_port = 0; - peer_host = IP_Address(); - r_received = total_read; - return ERR_FILE_EOF; - - } else { - - to_read -= read; - total_read += read; - }; - }; - - r_received = total_read; - - return OK; -}; - -void StreamPeerTCPPosix::set_no_delay(bool p_enabled) { - - ERR_FAIL_COND(!is_connected_to_host()); - int flag = p_enabled ? 1 : 0; - if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) < 0) { - ERR_PRINT("Unable to set TCP no delay option"); - } -} - -bool StreamPeerTCPPosix::is_connected_to_host() const { - - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return false; - }; - if (status != STATUS_CONNECTED) { - return true; - }; - - return (sockfd != -1); -}; - -StreamPeerTCP::Status StreamPeerTCPPosix::get_status() const { - - if (status == STATUS_CONNECTING) { - _poll_connection(); - }; - - return status; -}; - -void StreamPeerTCPPosix::disconnect_from_host() { - - if (sockfd != -1) - close(sockfd); - - sock_type = IP::TYPE_NONE; - sockfd = -1; - - status = STATUS_NONE; - peer_port = 0; - peer_host = IP_Address(); -}; - -Error StreamPeerTCPPosix::put_data(const uint8_t *p_data, int p_bytes) { - - int total; - return write(p_data, p_bytes, total, true); -}; - -Error StreamPeerTCPPosix::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { - - return write(p_data, p_bytes, r_sent, false); -}; - -Error StreamPeerTCPPosix::get_data(uint8_t *p_buffer, int p_bytes) { - - int total; - return read(p_buffer, p_bytes, total, true); -}; - -Error StreamPeerTCPPosix::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { - - return read(p_buffer, p_bytes, r_received, false); -}; - -int StreamPeerTCPPosix::get_available_bytes() const { - - unsigned long len; - int ret = ioctl(sockfd, FIONREAD, &len); - ERR_FAIL_COND_V(ret == -1, 0) - return len; -} -IP_Address StreamPeerTCPPosix::get_connected_host() const { - - return peer_host; -}; - -uint16_t StreamPeerTCPPosix::get_connected_port() const { - - return peer_port; -}; - -StreamPeerTCPPosix::StreamPeerTCPPosix() { - - sock_type = IP::TYPE_NONE; - sockfd = -1; - status = STATUS_NONE; - peer_port = 0; -}; - -StreamPeerTCPPosix::~StreamPeerTCPPosix() { - - disconnect_from_host(); -}; - -#endif diff --git a/drivers/unix/stream_peer_tcp_posix.h b/drivers/unix/stream_peer_tcp_posix.h deleted file mode 100644 index bcebe57771..0000000000 --- a/drivers/unix/stream_peer_tcp_posix.h +++ /dev/null @@ -1,90 +0,0 @@ -/*************************************************************************/ -/* stream_peer_tcp_posix.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. */ -/*************************************************************************/ - -#ifdef UNIX_ENABLED - -#ifndef STREAM_PEER_TCP_POSIX_H -#define STREAM_PEER_TCP_POSIX_H - -#include "core/io/ip_address.h" -#include "core/io/stream_peer_tcp.h" -#include "error_list.h" - -class StreamPeerTCPPosix : public StreamPeerTCP { - -protected: - mutable Status status; - - IP::Type sock_type; - int sockfd; - - Error _block(int p_sockfd, bool p_read, bool p_write) const; - - Error _poll_connection() const; - - IP_Address peer_host; - int peer_port; - - Error write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block); - Error read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block); - - static StreamPeerTCP *_create(); - -public: - virtual Error connect_to_host(const IP_Address &p_host, uint16_t p_port); - - virtual Error put_data(const uint8_t *p_data, int p_bytes); - virtual Error put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent); - - virtual Error get_data(uint8_t *p_buffer, int p_bytes); - virtual Error get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received); - - virtual int get_available_bytes() const; - - void set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type); - - virtual IP_Address get_connected_host() const; - virtual uint16_t get_connected_port() const; - - virtual bool is_connected_to_host() const; - virtual Status get_status() const; - virtual void disconnect_from_host(); - - virtual void set_no_delay(bool p_enabled); - - static void make_default(); - - StreamPeerTCPPosix(); - ~StreamPeerTCPPosix(); -}; - -#endif // TCP_CLIENT_POSIX_H - -#endif diff --git a/drivers/unix/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp index 727672458c..c7b4daf4ad 100644 --- a/drivers/unix/syslog_logger.cpp +++ b/drivers/unix/syslog_logger.cpp @@ -31,7 +31,7 @@ #ifdef UNIX_ENABLED #include "syslog_logger.h" -#include "print_string.h" +#include "core/print_string.h" #include <syslog.h> void SyslogLogger::logv(const char *p_format, va_list p_list, bool p_err) { diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h index 40bf26cee1..745264ab6f 100644 --- a/drivers/unix/syslog_logger.h +++ b/drivers/unix/syslog_logger.h @@ -33,7 +33,7 @@ #ifdef UNIX_ENABLED -#include "io/logger.h" +#include "core/io/logger.h" class SyslogLogger : public Logger { public: @@ -45,4 +45,4 @@ public: #endif -#endif
\ No newline at end of file +#endif diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp deleted file mode 100644 index 67ab981f46..0000000000 --- a/drivers/unix/tcp_server_posix.cpp +++ /dev/null @@ -1,207 +0,0 @@ -/*************************************************************************/ -/* tcp_server_posix.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 "tcp_server_posix.h" -#include "stream_peer_tcp_posix.h" - -#ifdef UNIX_ENABLED - -#include <poll.h> - -#include <errno.h> -#include <netdb.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/types.h> -#include <unistd.h> -#ifndef NO_FCNTL -#ifdef __HAIKU__ -#include <fcntl.h> -#else -#include <sys/fcntl.h> -#endif -#else -#include <sys/ioctl.h> -#endif -#ifdef JAVASCRIPT_ENABLED -#include <arpa/inet.h> -#endif -#include <assert.h> -#include <netinet/in.h> -#include <sys/socket.h> - -#include "drivers/unix/socket_helpers.h" - -TCP_Server *TCPServerPosix::_create() { - - return memnew(TCPServerPosix); -}; - -void TCPServerPosix::make_default() { - - TCP_Server::_create = TCPServerPosix::_create; -}; - -Error TCPServerPosix::listen(uint16_t p_port, const IP_Address &p_bind_address) { - - ERR_FAIL_COND_V(listen_sockfd != -1, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - - int sockfd; -#ifdef __OpenBSD__ - sock_type = IP::TYPE_IPV4; // OpenBSD does not support dual stacking, fallback to IPv4 only. -#else - sock_type = IP::TYPE_ANY; -#endif - - // If the bind address is valid use its type as the socket type - if (p_bind_address.is_valid()) - sock_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - sockfd = _socket_create(sock_type, SOCK_STREAM, IPPROTO_TCP); - - ERR_FAIL_COND_V(sockfd == -1, FAILED); - -#ifndef NO_FCNTL - if (fcntl(sockfd, F_SETFL, O_NONBLOCK) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#else - int bval = 1; - if (ioctl(sockfd, FIONBIO, &bval) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#endif - - int reuse = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) { - WARN_PRINT("REUSEADDR failed!") - } - - struct sockaddr_storage addr; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, sock_type, p_bind_address); - - if (bind(sockfd, (struct sockaddr *)&addr, addr_size) != -1) { - - if (::listen(sockfd, 1) == -1) { - - close(sockfd); - ERR_FAIL_V(FAILED); - }; - } else { - close(sockfd); - return ERR_ALREADY_IN_USE; - }; - - if (listen_sockfd != -1) { - stop(); - }; - - listen_sockfd = sockfd; - - return OK; -}; - -bool TCPServerPosix::is_connection_available() const { - - if (listen_sockfd == -1) { - return false; - }; - - struct pollfd pfd; - pfd.fd = listen_sockfd; - pfd.events = POLLIN; - pfd.revents = 0; - - int ret = poll(&pfd, 1, 0); - ERR_FAIL_COND_V(ret < 0, FAILED); - - if (ret && (pfd.revents & POLLIN)) { - return true; - }; - - return false; -}; - -Ref<StreamPeerTCP> TCPServerPosix::take_connection() { - - if (!is_connection_available()) { - return Ref<StreamPeerTCP>(); - }; - - struct sockaddr_storage their_addr; - socklen_t size = sizeof(their_addr); - int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &size); - ERR_FAIL_COND_V(fd == -1, Ref<StreamPeerTCP>()); -#ifndef NO_FCNTL - if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#else - int bval = 1; - if (ioctl(fd, FIONBIO, &bval) < 0) { - WARN_PRINT("Error setting socket as non blocking"); - } -#endif - - Ref<StreamPeerTCPPosix> conn = memnew(StreamPeerTCPPosix); - IP_Address ip; - - int port = 0; - _set_ip_addr_port(ip, port, &their_addr); - - conn->set_socket(fd, ip, port, sock_type); - - return conn; -}; - -void TCPServerPosix::stop() { - - if (listen_sockfd != -1) { - int ret = close(listen_sockfd); - ERR_FAIL_COND(ret != 0); - }; - - listen_sockfd = -1; - sock_type = IP::TYPE_NONE; -}; - -TCPServerPosix::TCPServerPosix() { - - listen_sockfd = -1; - sock_type = IP::TYPE_NONE; -}; - -TCPServerPosix::~TCPServerPosix() { - - stop(); -}; -#endif diff --git a/drivers/unix/tcp_server_posix.h b/drivers/unix/tcp_server_posix.h deleted file mode 100644 index c749314fb3..0000000000 --- a/drivers/unix/tcp_server_posix.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************/ -/* tcp_server_posix.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 TCP_SERVER_POSIX_H -#define TCP_SERVER_POSIX_H - -#ifdef UNIX_ENABLED -#include "core/io/tcp_server.h" - -class TCPServerPosix : public TCP_Server { - - int listen_sockfd; - IP::Type sock_type; - - static TCP_Server *_create(); - -public: - virtual Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*")); - virtual bool is_connection_available() const; - virtual Ref<StreamPeerTCP> take_connection(); - - virtual void stop(); - - static void make_default(); - - TCPServerPosix(); - ~TCPServerPosix(); -}; - -#endif // TCP_SERVER_POSIX_H -#endif diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp index a73b40a6f2..54bbbf2dad 100644 --- a/drivers/unix/thread_posix.cpp +++ b/drivers/unix/thread_posix.cpp @@ -29,7 +29,7 @@ /*************************************************************************/ #include "thread_posix.h" -#include "script_language.h" +#include "core/script_language.h" #if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS) @@ -37,8 +37,8 @@ #include <pthread_np.h> #endif +#include "core/os/memory.h" #include "core/safe_refcount.h" -#include "os/memory.h" static pthread_key_t _create_thread_id_key() { pthread_key_t key; @@ -103,8 +103,6 @@ void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { Error ThreadPosix::set_name_func_posix(const String &p_name) { - pthread_t running_thread = pthread_self(); - #ifdef PTHREAD_NO_RENAME return ERR_UNAVAILABLE; @@ -117,6 +115,7 @@ Error ThreadPosix::set_name_func_posix(const String &p_name) { #else + pthread_t running_thread = pthread_self(); #ifdef PTHREAD_BSD_SET_NAME pthread_set_name_np(running_thread, p_name.utf8().get_data()); int err = 0; // Open/FreeBSD ignore errors in this function diff --git a/drivers/unix/thread_posix.h b/drivers/unix/thread_posix.h index ea2de61bd5..20d103232e 100644 --- a/drivers/unix/thread_posix.h +++ b/drivers/unix/thread_posix.h @@ -37,7 +37,7 @@ #if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS) -#include "os/thread.h" +#include "core/os/thread.h" #include <pthread.h> #include <sys/types.h> diff --git a/drivers/wasapi/SCsub b/drivers/wasapi/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/wasapi/SCsub +++ b/drivers/wasapi/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 11abe3256e..8665f701b1 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -32,8 +32,8 @@ #include "audio_driver_wasapi.h" -#include "os/os.h" -#include "project_settings.h" +#include "core/os/os.h" +#include "core/project_settings.h" #include <functiondiscoverykeys.h> @@ -65,7 +65,6 @@ const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient); #define CAPTURE_BUFFER_CHANNELS 2 -static StringName capture_device_id; static bool default_render_device_changed = false; static bool default_capture_device_changed = false; @@ -128,7 +127,6 @@ public: default_render_device_changed = true; } else if (flow == eCapture) { default_capture_device_changed = true; - capture_device_id = String(pwstrDeviceId); } } @@ -338,10 +336,7 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) { HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); - // Set the buffer size - input_buffer.resize(max_frames * CAPTURE_BUFFER_CHANNELS); - input_position = 0; - input_size = 0; + input_buffer_init(max_frames); return OK; } @@ -659,6 +654,9 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { if (err == OK) { ad->start(); } + + avail_frames = 0; + write_ofs = 0; } if (ad->audio_input.active) { @@ -795,19 +793,18 @@ Error AudioDriverWASAPI::capture_start() { return err; } - if (audio_input.active == false) { - audio_input.audio_client->Start(); - audio_input.active = true; - - return OK; + if (audio_input.active) { + return FAILED; } - return FAILED; + audio_input.audio_client->Start(); + audio_input.active = true; + return OK; } Error AudioDriverWASAPI::capture_stop() { - if (audio_input.active == true) { + if (audio_input.active) { audio_input.audio_client->Stop(); audio_input.active = false; diff --git a/drivers/windows/SCsub b/drivers/windows/SCsub index ee39fd2631..28b315ae66 100644 --- a/drivers/windows/SCsub +++ b/drivers/windows/SCsub @@ -3,5 +3,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index cf4d82fb07..589e9e0870 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -32,9 +32,9 @@ #include "dir_access_windows.h" -#include "os/memory.h" +#include "core/os/memory.h" +#include "core/print_string.h" -#include "print_string.h" #include <stdio.h> #include <wchar.h> #include <windows.h> diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h index b18c8f5b5d..9f5d0b6d93 100644 --- a/drivers/windows/dir_access_windows.h +++ b/drivers/windows/dir_access_windows.h @@ -33,7 +33,7 @@ #ifdef WINDOWS_ENABLED -#include "os/dir_access.h" +#include "core/os/dir_access.h" /** @author Juan Linietsky <reduz@gmail.com> diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index b4492a2022..2582478259 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -114,7 +114,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { path = path + ".tmp"; } - f = _wfopen(path.c_str(), mode_string); + _wfopen_s(&f, path.c_str(), mode_string); if (f == NULL) { last_error = ERR_FILE_CANT_OPEN; @@ -278,7 +278,7 @@ bool FileAccessWindows::file_exists(const String &p_name) { FILE *g; //printf("opening file %s\n", p_fname.c_str()); String filename = fix_path(p_name); - g = _wfopen(filename.c_str(), L"rb"); + _wfopen_s(&g, filename.c_str(), L"rb"); if (g == NULL) { return false; diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 0462c1e942..6f985e68b4 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -33,13 +33,15 @@ #ifdef WINDOWS_ENABLED -#include "os/file_access.h" -#include "os/memory.h" +#include "core/os/file_access.h" +#include "core/os/memory.h" + #include <stdio.h> /** @author Juan Linietsky <reduzio@gmail.com> */ + class FileAccessWindows : public FileAccess { FILE *f; diff --git a/drivers/windows/mutex_windows.cpp b/drivers/windows/mutex_windows.cpp index 359a79209c..9fc6485be3 100644 --- a/drivers/windows/mutex_windows.cpp +++ b/drivers/windows/mutex_windows.cpp @@ -29,7 +29,8 @@ /*************************************************************************/ #include "mutex_windows.h" -#include "os/memory.h" + +#include "core/os/memory.h" #ifdef WINDOWS_ENABLED diff --git a/drivers/windows/mutex_windows.h b/drivers/windows/mutex_windows.h index 4dff2c2456..5c3a8eb331 100644 --- a/drivers/windows/mutex_windows.h +++ b/drivers/windows/mutex_windows.h @@ -33,11 +33,14 @@ #ifdef WINDOWS_ENABLED -#include "os/mutex.h" +#include "core/os/mutex.h" + #include <windows.h> + /** @author Juan Linietsky <reduzio@gmail.com> */ + class MutexWindows : public Mutex { #ifdef WINDOWS_USE_MUTEX diff --git a/drivers/windows/packet_peer_udp_winsock.cpp b/drivers/windows/packet_peer_udp_winsock.cpp deleted file mode 100644 index 609096d02e..0000000000 --- a/drivers/windows/packet_peer_udp_winsock.cpp +++ /dev/null @@ -1,298 +0,0 @@ -/*************************************************************************/ -/* packet_peer_udp_winsock.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. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#include "packet_peer_udp_winsock.h" - -#include <winsock2.h> -#include <ws2tcpip.h> - -#include "drivers/unix/socket_helpers.h" - -int PacketPeerUDPWinsock::get_available_packet_count() const { - - Error err = const_cast<PacketPeerUDPWinsock *>(this)->_poll(false); - if (err != OK) - return 0; - - return queue_count; -} - -Error PacketPeerUDPWinsock::get_packet(const uint8_t **r_buffer, int &r_buffer_size) { - - Error err = const_cast<PacketPeerUDPWinsock *>(this)->_poll(false); - if (err != OK) - return err; - if (queue_count == 0) - return ERR_UNAVAILABLE; - - uint32_t size; - uint8_t type; - rb.read(&type, 1, true); - if (type == IP::TYPE_IPV4) { - uint8_t ip[4]; - rb.read(ip, 4, true); - packet_ip.set_ipv4(ip); - } else { - uint8_t ip[16]; - rb.read(ip, 16, true); - packet_ip.set_ipv6(ip); - }; - rb.read((uint8_t *)&packet_port, 4, true); - rb.read((uint8_t *)&size, 4, true); - rb.read(packet_buffer, size, true); - --queue_count; - *r_buffer = packet_buffer; - r_buffer_size = size; - return OK; -} -Error PacketPeerUDPWinsock::put_packet(const uint8_t *p_buffer, int p_buffer_size) { - - ERR_FAIL_COND_V(!peer_addr.is_valid(), ERR_UNCONFIGURED); - - if (sock_type == IP::TYPE_NONE) - sock_type = peer_addr.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - int sock = _get_socket(); - ERR_FAIL_COND_V(sock == -1, FAILED); - struct sockaddr_storage addr; - size_t addr_size = _set_sockaddr(&addr, peer_addr, peer_port, sock_type); - - _set_sock_blocking(blocking); - - errno = 0; - int err; - while ((err = sendto(sock, (const char *)p_buffer, p_buffer_size, 0, (struct sockaddr *)&addr, addr_size)) != p_buffer_size) { - - if (WSAGetLastError() != WSAEWOULDBLOCK) { - return FAILED; - } else if (!blocking) { - return ERR_UNAVAILABLE; - } - } - - return OK; -} - -int PacketPeerUDPWinsock::get_max_packet_size() const { - - return 512; // uhm maybe not -} - -void PacketPeerUDPWinsock::_set_sock_blocking(bool p_blocking) { - - if (sock_blocking == p_blocking) - return; - - sock_blocking = p_blocking; - unsigned long par = sock_blocking ? 0 : 1; - if (ioctlsocket(sockfd, FIONBIO, &par)) { - perror("setting non-block mode"); - //close(); - //return -1; - }; -} - -Error PacketPeerUDPWinsock::listen(int p_port, const IP_Address &p_bind_address, int p_recv_buffer_size) { - - ERR_FAIL_COND_V(sockfd != -1, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - - sock_type = IP::TYPE_ANY; - - if (p_bind_address.is_valid()) - sock_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - int sock = _get_socket(); - if (sock == -1) - return ERR_CANT_CREATE; - - struct sockaddr_storage addr = { 0 }; - size_t addr_size = _set_listen_sockaddr(&addr, p_port, sock_type, IP_Address()); - - if (bind(sock, (struct sockaddr *)&addr, addr_size) == -1) { - close(); - return ERR_UNAVAILABLE; - } - - printf("UDP Connection listening on port %i\n", p_port); - rb.resize(nearest_shift(p_recv_buffer_size)); - return OK; -} - -void PacketPeerUDPWinsock::close() { - - if (sockfd != -1) - ::closesocket(sockfd); - sockfd = -1; - sock_type = IP::TYPE_NONE; - rb.resize(16); - queue_count = 0; -} - -Error PacketPeerUDPWinsock::wait() { - - return _poll(true); -} -Error PacketPeerUDPWinsock::_poll(bool p_wait) { - - if (sockfd == -1) { - return FAILED; - } - - _set_sock_blocking(p_wait); - - struct sockaddr_storage from = { 0 }; - int len = sizeof(struct sockaddr_storage); - int ret; - while ((ret = recvfrom(sockfd, (char *)recv_buffer, MIN((int)sizeof(recv_buffer), MAX(rb.space_left() - 24, 0)), 0, (struct sockaddr *)&from, &len)) > 0) { - - uint32_t port = 0; - - if (from.ss_family == AF_INET) { - uint8_t type = (uint8_t)IP::TYPE_IPV4; - rb.write(&type, 1); - struct sockaddr_in *sin_from = (struct sockaddr_in *)&from; - rb.write((uint8_t *)&sin_from->sin_addr, 4); - port = ntohs(sin_from->sin_port); - - } else if (from.ss_family == AF_INET6) { - - uint8_t type = (uint8_t)IP::TYPE_IPV6; - rb.write(&type, 1); - - struct sockaddr_in6 *s6_from = (struct sockaddr_in6 *)&from; - rb.write((uint8_t *)&s6_from->sin6_addr, 16); - - port = ntohs(s6_from->sin6_port); - - } else { - // WARN_PRINT("Ignoring packet with unknown address family"); - uint8_t type = (uint8_t)IP::TYPE_NONE; - rb.write(&type, 1); - }; - - rb.write((uint8_t *)&port, 4); - rb.write((uint8_t *)&ret, 4); - rb.write(recv_buffer, ret); - - len = sizeof(struct sockaddr_storage); - ++queue_count; - if (p_wait) - break; - }; - - if (ret == SOCKET_ERROR) { - int error = WSAGetLastError(); - - if (error == WSAEWOULDBLOCK) { - // Expected when doing non-blocking sockets, retry later. - } else if (error == WSAECONNRESET) { - // If the remote target does not accept messages, this error may occur, but is harmless. - // Once the remote target gets available, this message will disappear for new messages. - } else { - close(); - return FAILED; - } - } - - if (ret == 0) { - close(); - return FAILED; - }; - - return OK; -} - -bool PacketPeerUDPWinsock::is_listening() const { - - return sockfd != -1; -} - -IP_Address PacketPeerUDPWinsock::get_packet_address() const { - - return packet_ip; -} - -int PacketPeerUDPWinsock::get_packet_port() const { - - return packet_port; -} - -int PacketPeerUDPWinsock::_get_socket() { - - ERR_FAIL_COND_V(sock_type == IP::TYPE_NONE, -1); - - if (sockfd != -1) - return sockfd; - - sockfd = _socket_create(sock_type, SOCK_DGRAM, IPPROTO_UDP); - - if (sockfd != -1) - _set_sock_blocking(false); - - return sockfd; -} - -void PacketPeerUDPWinsock::set_dest_address(const IP_Address &p_address, int p_port) { - - peer_addr = p_address; - peer_port = p_port; -} - -void PacketPeerUDPWinsock::make_default() { - - PacketPeerUDP::_create = PacketPeerUDPWinsock::_create; -}; - -PacketPeerUDP *PacketPeerUDPWinsock::_create() { - - return memnew(PacketPeerUDPWinsock); -}; - -PacketPeerUDPWinsock::PacketPeerUDPWinsock() { - - blocking = true; - sock_blocking = true; - sockfd = -1; - packet_port = 0; - queue_count = 0; - peer_port = 0; - sock_type = IP::TYPE_NONE; - rb.resize(16); -} - -PacketPeerUDPWinsock::~PacketPeerUDPWinsock() { - - close(); -} - -#endif diff --git a/drivers/windows/packet_peer_udp_winsock.h b/drivers/windows/packet_peer_udp_winsock.h deleted file mode 100644 index 8d575c2033..0000000000 --- a/drivers/windows/packet_peer_udp_winsock.h +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************/ -/* packet_peer_udp_winsock.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. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#ifndef PACKET_PEER_UDP_WINSOCK_H -#define PACKET_PEER_UDP_WINSOCK_H - -#include "io/packet_peer_udp.h" -#include "ring_buffer.h" - -class PacketPeerUDPWinsock : public PacketPeerUDP { - - enum { - PACKET_BUFFER_SIZE = 65536 - }; - - RingBuffer<uint8_t> rb; - uint8_t recv_buffer[PACKET_BUFFER_SIZE]; - uint8_t packet_buffer[PACKET_BUFFER_SIZE]; - IP_Address packet_ip; - int packet_port; - int queue_count; - int sockfd; - bool sock_blocking; - IP::Type sock_type; - - IP_Address peer_addr; - int peer_port; - - _FORCE_INLINE_ int _get_socket(); - - static PacketPeerUDP *_create(); - - void _set_sock_blocking(bool p_blocking); - - Error _poll(bool p_wait); - -public: - virtual int get_available_packet_count() const; - virtual Error get_packet(const uint8_t **r_buffer, int &r_buffer_size); - virtual Error put_packet(const uint8_t *p_buffer, int p_buffer_size); - - virtual int get_max_packet_size() const; - - virtual Error listen(int p_port, const IP_Address &p_bind_address = IP_Address("*"), int p_recv_buffer_size = 65536); - virtual void close(); - virtual Error wait(); - virtual bool is_listening() const; - - virtual IP_Address get_packet_address() const; - virtual int get_packet_port() const; - - virtual void set_dest_address(const IP_Address &p_address, int p_port); - - static void make_default(); - PacketPeerUDPWinsock(); - ~PacketPeerUDPWinsock(); -}; -#endif // PACKET_PEER_UDP_WINSOCK_H - -#endif diff --git a/drivers/windows/rw_lock_windows.cpp b/drivers/windows/rw_lock_windows.cpp index 29c24d3d02..ef00141928 100644 --- a/drivers/windows/rw_lock_windows.cpp +++ b/drivers/windows/rw_lock_windows.cpp @@ -32,8 +32,9 @@ #include "rw_lock_windows.h" -#include "error_macros.h" -#include "os/memory.h" +#include "core/error_macros.h" +#include "core/os/memory.h" + #include <stdio.h> void RWLockWindows::read_lock() { diff --git a/drivers/windows/rw_lock_windows.h b/drivers/windows/rw_lock_windows.h index fdce28574a..742a0930d4 100644 --- a/drivers/windows/rw_lock_windows.h +++ b/drivers/windows/rw_lock_windows.h @@ -33,7 +33,8 @@ #if defined(WINDOWS_ENABLED) -#include "os/rw_lock.h" +#include "core/os/rw_lock.h" + #include <windows.h> class RWLockWindows : public RWLock { diff --git a/drivers/windows/semaphore_windows.cpp b/drivers/windows/semaphore_windows.cpp index 25fced93ce..34dd387705 100644 --- a/drivers/windows/semaphore_windows.cpp +++ b/drivers/windows/semaphore_windows.cpp @@ -32,7 +32,7 @@ #if defined(WINDOWS_ENABLED) -#include "os/memory.h" +#include "core/os/memory.h" Error SemaphoreWindows::wait() { diff --git a/drivers/windows/semaphore_windows.h b/drivers/windows/semaphore_windows.h index e099ee437a..1e2f9c152e 100644 --- a/drivers/windows/semaphore_windows.h +++ b/drivers/windows/semaphore_windows.h @@ -31,14 +31,16 @@ #ifndef SEMAPHORE_WINDOWS_H #define SEMAPHORE_WINDOWS_H -#include "os/semaphore.h" +#include "core/os/semaphore.h" #ifdef WINDOWS_ENABLED #include <windows.h> + /** @author Juan Linietsky <reduzio@gmail.com> */ + class SemaphoreWindows : public Semaphore { mutable HANDLE semaphore; diff --git a/drivers/windows/shell_windows.h b/drivers/windows/shell_windows.h index 41cc6b72a2..98972a9bb1 100644 --- a/drivers/windows/shell_windows.h +++ b/drivers/windows/shell_windows.h @@ -31,12 +31,14 @@ #ifndef SHELL_WINDOWS_H #define SHELL_WINDOWS_H -#include "os/shell.h" +#include "core/os/shell.h" #ifdef WINDOWS_ENABLED + /** @author Juan Linietsky <reduzio@gmail.com> */ + class ShellWindows : public Shell { public: virtual void execute(String p_path); diff --git a/drivers/windows/stream_peer_tcp_winsock.cpp b/drivers/windows/stream_peer_tcp_winsock.cpp deleted file mode 100644 index 19c937170b..0000000000 --- a/drivers/windows/stream_peer_tcp_winsock.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/*************************************************************************/ -/* stream_peer_tcp_winsock.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. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#include "stream_peer_tcp_winsock.h" - -#include <winsock2.h> -#include <ws2tcpip.h> - -#include "drivers/unix/socket_helpers.h" - -int winsock_refcount = 0; - -StreamPeerTCP *StreamPeerTCPWinsock::_create() { - - return memnew(StreamPeerTCPWinsock); -}; - -void StreamPeerTCPWinsock::make_default() { - - StreamPeerTCP::_create = StreamPeerTCPWinsock::_create; - - if (winsock_refcount == 0) { - WSADATA data; - WSAStartup(MAKEWORD(2, 2), &data); - }; - ++winsock_refcount; -}; - -void StreamPeerTCPWinsock::cleanup() { - - --winsock_refcount; - if (winsock_refcount == 0) { - - WSACleanup(); - }; -}; - -Error StreamPeerTCPWinsock::_block(int p_sockfd, bool p_read, bool p_write) const { - - fd_set read, write; - FD_ZERO(&read); - FD_ZERO(&write); - - if (p_read) - FD_SET(p_sockfd, &read); - if (p_write) - FD_SET(p_sockfd, &write); - - int ret = select(p_sockfd + 1, &read, &write, NULL, NULL); // block forever - return ret < 0 ? FAILED : OK; -}; - -Error StreamPeerTCPWinsock::_poll_connection() const { - - ERR_FAIL_COND_V(status != STATUS_CONNECTING || sockfd == INVALID_SOCKET, FAILED); - - struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, peer_host, peer_port, sock_type); - - if (::connect(sockfd, (struct sockaddr *)&their_addr, addr_size) == SOCKET_ERROR) { - - int err = WSAGetLastError(); - if (err == WSAEISCONN) { - status = STATUS_CONNECTED; - return OK; - }; - - if (err == WSAEINPROGRESS || err == WSAEALREADY) { - return OK; - } - - status = STATUS_ERROR; - return ERR_CONNECTION_ERROR; - } else { - - status = STATUS_CONNECTED; - return OK; - }; - - return OK; -}; - -Error StreamPeerTCPWinsock::write(const uint8_t *p_data, int p_bytes, int &r_sent, bool p_block) { - - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - - if (_poll_connection() != OK) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - r_sent = 0; - return OK; - }; - }; - - int data_to_send = p_bytes; - const uint8_t *offset = p_data; - if (sockfd == -1) return FAILED; - int total_sent = 0; - - while (data_to_send) { - - int sent_amount = send(sockfd, (const char *)offset, data_to_send, 0); - - if (sent_amount == -1) { - - if (WSAGetLastError() != WSAEWOULDBLOCK) { - - perror("Nothing sent"); - disconnect_from_host(); - ERR_PRINT("Server disconnected!\n"); - return FAILED; - }; - - if (!p_block) { - r_sent = total_sent; - return OK; - }; - - _block(sockfd, false, true); - } else { - - data_to_send -= sent_amount; - offset += sent_amount; - total_sent += sent_amount; - }; - } - - r_sent = total_sent; - - return OK; -}; - -Error StreamPeerTCPWinsock::read(uint8_t *p_buffer, int p_bytes, int &r_received, bool p_block) { - - if (!is_connected_to_host()) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - - if (_poll_connection() != OK) { - - return FAILED; - }; - - if (status != STATUS_CONNECTED) { - r_received = 0; - return OK; - }; - }; - - int to_read = p_bytes; - int total_read = 0; - - while (to_read) { - - int read = recv(sockfd, (char *)p_buffer + total_read, to_read, 0); - - if (read == -1) { - - if (WSAGetLastError() != WSAEWOULDBLOCK) { - - perror("Nothing read"); - disconnect_from_host(); - ERR_PRINT("Server disconnected!\n"); - return FAILED; - }; - - if (!p_block) { - - r_received = total_read; - return OK; - }; - _block(sockfd, true, false); - } else if (read == 0) { - disconnect_from_host(); - r_received = total_read; - return ERR_FILE_EOF; - } else { - - to_read -= read; - total_read += read; - }; - }; - - r_received = total_read; - - return OK; -}; - -Error StreamPeerTCPWinsock::put_data(const uint8_t *p_data, int p_bytes) { - - int total; - return write(p_data, p_bytes, total, true); -}; - -Error StreamPeerTCPWinsock::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) { - - return write(p_data, p_bytes, r_sent, false); -}; - -Error StreamPeerTCPWinsock::get_data(uint8_t *p_buffer, int p_bytes) { - - int total; - return read(p_buffer, p_bytes, total, true); -}; - -Error StreamPeerTCPWinsock::get_partial_data(uint8_t *p_buffer, int p_bytes, int &r_received) { - - return read(p_buffer, p_bytes, r_received, false); -}; - -StreamPeerTCP::Status StreamPeerTCPWinsock::get_status() const { - - if (status == STATUS_CONNECTING) { - _poll_connection(); - }; - - return status; -}; - -bool StreamPeerTCPWinsock::is_connected_to_host() const { - - if (status == STATUS_NONE || status == STATUS_ERROR) { - - return false; - }; - if (status != STATUS_CONNECTED) { - return true; - }; - - return (sockfd != INVALID_SOCKET); -}; - -void StreamPeerTCPWinsock::disconnect_from_host() { - - if (sockfd != INVALID_SOCKET) - closesocket(sockfd); - sockfd = INVALID_SOCKET; - sock_type = IP::TYPE_NONE; - - status = STATUS_NONE; - - peer_host = IP_Address(); - peer_port = 0; -}; - -void StreamPeerTCPWinsock::set_socket(int p_sockfd, IP_Address p_host, int p_port, IP::Type p_sock_type) { - - sockfd = p_sockfd; - sock_type = p_sock_type; - status = STATUS_CONNECTING; - peer_host = p_host; - peer_port = p_port; -}; - -Error StreamPeerTCPWinsock::connect_to_host(const IP_Address &p_host, uint16_t p_port) { - - ERR_FAIL_COND_V(!p_host.is_valid(), ERR_INVALID_PARAMETER); - - sock_type = p_host.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - sockfd = _socket_create(sock_type, SOCK_STREAM, IPPROTO_TCP); - if (sockfd == INVALID_SOCKET) { - ERR_PRINT("Socket creation failed!"); - disconnect_from_host(); - //perror("socket"); - return FAILED; - }; - - unsigned long par = 1; - if (ioctlsocket(sockfd, FIONBIO, &par)) { - perror("setting non-block mode"); - disconnect_from_host(); - return FAILED; - }; - - struct sockaddr_storage their_addr; - size_t addr_size = _set_sockaddr(&their_addr, p_host, p_port, sock_type); - - if (::connect(sockfd, (struct sockaddr *)&their_addr, addr_size) == SOCKET_ERROR) { - - if (WSAGetLastError() != WSAEWOULDBLOCK) { - ERR_PRINT("Connection to remote host failed!"); - disconnect_from_host(); - return FAILED; - }; - status = STATUS_CONNECTING; - } else { - status = STATUS_CONNECTED; - }; - - peer_host = p_host; - peer_port = p_port; - - return OK; -}; - -void StreamPeerTCPWinsock::set_no_delay(bool p_enabled) { - ERR_FAIL_COND(!is_connected_to_host()); - int flag = p_enabled ? 1 : 0; - if (setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(int)) != 0) { - ERR_PRINT("Unable to set TCP no delay option"); - } -} - -int StreamPeerTCPWinsock::get_available_bytes() const { - - unsigned long len; - int ret = ioctlsocket(sockfd, FIONREAD, &len); - ERR_FAIL_COND_V(ret == -1, 0) - return len; -} - -IP_Address StreamPeerTCPWinsock::get_connected_host() const { - - return peer_host; -}; - -uint16_t StreamPeerTCPWinsock::get_connected_port() const { - - return peer_port; -}; - -StreamPeerTCPWinsock::StreamPeerTCPWinsock() { - - sock_type = IP::TYPE_NONE; - sockfd = INVALID_SOCKET; - status = STATUS_NONE; - peer_port = 0; -}; - -StreamPeerTCPWinsock::~StreamPeerTCPWinsock() { - - disconnect_from_host(); -}; - -#endif diff --git a/drivers/windows/tcp_server_winsock.cpp b/drivers/windows/tcp_server_winsock.cpp deleted file mode 100644 index ddb955549f..0000000000 --- a/drivers/windows/tcp_server_winsock.cpp +++ /dev/null @@ -1,189 +0,0 @@ -/*************************************************************************/ -/* tcp_server_winsock.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. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#include "tcp_server_winsock.h" - -#include "stream_peer_tcp_winsock.h" - -#include <winsock2.h> -#include <ws2tcpip.h> - -#include "drivers/unix/socket_helpers.h" - -extern int winsock_refcount; - -TCP_Server *TCPServerWinsock::_create() { - - return memnew(TCPServerWinsock); -}; - -void TCPServerWinsock::make_default() { - - TCP_Server::_create = TCPServerWinsock::_create; - - if (winsock_refcount == 0) { - WSADATA data; - WSAStartup(MAKEWORD(2, 2), &data); - }; - ++winsock_refcount; -}; - -void TCPServerWinsock::cleanup() { - - --winsock_refcount; - if (winsock_refcount == 0) { - - WSACleanup(); - }; -}; - -Error TCPServerWinsock::listen(uint16_t p_port, const IP_Address &p_bind_address) { - - ERR_FAIL_COND_V(listen_sockfd != -1, ERR_ALREADY_IN_USE); - ERR_FAIL_COND_V(!p_bind_address.is_valid() && !p_bind_address.is_wildcard(), ERR_INVALID_PARAMETER); - - int sockfd; - sock_type = IP::TYPE_ANY; - - // If the bind address is valid use its type as the socket type - if (p_bind_address.is_valid()) - sock_type = p_bind_address.is_ipv4() ? IP::TYPE_IPV4 : IP::TYPE_IPV6; - - sockfd = _socket_create(sock_type, SOCK_STREAM, IPPROTO_TCP); - ERR_FAIL_COND_V(sockfd == INVALID_SOCKET, FAILED); - - unsigned long par = 1; - if (ioctlsocket(sockfd, FIONBIO, &par)) { - perror("setting non-block mode"); - stop(); - return FAILED; - }; - - struct sockaddr_storage my_addr; - size_t addr_size = _set_listen_sockaddr(&my_addr, p_port, sock_type, p_bind_address); - - int reuse = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_REUSEADDR, (char *)&reuse, sizeof(reuse)) < 0) { - - printf("REUSEADDR failed!"); - } - - if (bind(sockfd, (struct sockaddr *)&my_addr, addr_size) != SOCKET_ERROR) { - - if (::listen(sockfd, SOMAXCONN) == SOCKET_ERROR) { - - closesocket(sockfd); - ERR_FAIL_V(FAILED); - }; - } else { - closesocket(sockfd); - return ERR_ALREADY_IN_USE; - }; - - if (listen_sockfd != INVALID_SOCKET) { - - stop(); - }; - - listen_sockfd = sockfd; - - return OK; -}; - -bool TCPServerWinsock::is_connection_available() const { - - if (listen_sockfd == -1) { - return false; - }; - - timeval timeout; - timeout.tv_sec = 0; - timeout.tv_usec = 0; - - fd_set pfd; - FD_ZERO(&pfd); - FD_SET(listen_sockfd, &pfd); - - int ret = select(listen_sockfd + 1, &pfd, NULL, NULL, &timeout); - ERR_FAIL_COND_V(ret < 0, 0); - - if (ret && (FD_ISSET(listen_sockfd, &pfd))) { - - return true; - }; - - return false; -}; - -Ref<StreamPeerTCP> TCPServerWinsock::take_connection() { - - if (!is_connection_available()) { - return NULL; - }; - - struct sockaddr_storage their_addr; - int sin_size = sizeof(their_addr); - int fd = accept(listen_sockfd, (struct sockaddr *)&their_addr, &sin_size); - ERR_FAIL_COND_V(fd == INVALID_SOCKET, NULL); - - Ref<StreamPeerTCPWinsock> conn = memnew(StreamPeerTCPWinsock); - IP_Address ip; - int port; - _set_ip_addr_port(ip, port, &their_addr); - - conn->set_socket(fd, ip, port, sock_type); - - return conn; -}; - -void TCPServerWinsock::stop() { - - if (listen_sockfd != INVALID_SOCKET) { - closesocket(listen_sockfd); - }; - - listen_sockfd = -1; - sock_type = IP::TYPE_NONE; -}; - -TCPServerWinsock::TCPServerWinsock() { - - listen_sockfd = INVALID_SOCKET; - sock_type = IP::TYPE_NONE; -}; - -TCPServerWinsock::~TCPServerWinsock() { - - stop(); -}; - -#endif diff --git a/drivers/windows/tcp_server_winsock.h b/drivers/windows/tcp_server_winsock.h deleted file mode 100644 index a6979db42d..0000000000 --- a/drivers/windows/tcp_server_winsock.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************/ -/* tcp_server_winsock.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. */ -/*************************************************************************/ - -#ifdef WINDOWS_ENABLED - -#ifndef TCP_SERVER_WINSOCK_H -#define TCP_SERVER_WINSOCK_H - -#include "core/io/tcp_server.h" - -class TCPServerWinsock : public TCP_Server { - - int listen_sockfd; - IP::Type sock_type; - - static TCP_Server *_create(); - -public: - virtual Error listen(uint16_t p_port, const IP_Address &p_bind_address = IP_Address("*")); - virtual bool is_connection_available() const; - virtual Ref<StreamPeerTCP> take_connection(); - - virtual void stop(); //stop listening - - static void make_default(); - static void cleanup(); - - TCPServerWinsock(); - ~TCPServerWinsock(); -}; - -#endif - -#endif diff --git a/drivers/windows/thread_windows.cpp b/drivers/windows/thread_windows.cpp index 5e0b017a5c..52dcfacdf8 100644 --- a/drivers/windows/thread_windows.cpp +++ b/drivers/windows/thread_windows.cpp @@ -32,7 +32,7 @@ #if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED) -#include "os/memory.h" +#include "core/os/memory.h" Thread::ID ThreadWindows::get_id() const { diff --git a/drivers/windows/thread_windows.h b/drivers/windows/thread_windows.h index d7a8389d9e..5d2838e54f 100644 --- a/drivers/windows/thread_windows.h +++ b/drivers/windows/thread_windows.h @@ -31,16 +31,17 @@ #ifndef THREAD_WINDOWS_H #define THREAD_WINDOWS_H -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - #ifdef WINDOWS_ENABLED -#include "os/thread.h" -#include "script_language.h" +#include "core/os/thread.h" +#include "core/script_language.h" + #include <windows.h> +/** + @author Juan Linietsky <reduzio@gmail.com> +*/ + class ThreadWindows : public Thread { ThreadCreateCallback callback; diff --git a/drivers/winmidi/SCsub b/drivers/winmidi/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/winmidi/SCsub +++ b/drivers/winmidi/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/winmidi/win_midi.cpp b/drivers/winmidi/win_midi.cpp index 63f7f13685..1d4bf1a1e2 100644 --- a/drivers/winmidi/win_midi.cpp +++ b/drivers/winmidi/win_midi.cpp @@ -31,7 +31,8 @@ #ifdef WINMIDI_ENABLED #include "win_midi.h" -#include "print_string.h" + +#include "core/print_string.h" void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) { diff --git a/drivers/winmidi/win_midi.h b/drivers/winmidi/win_midi.h index 1cf9b19b5d..87a349d5d1 100644 --- a/drivers/winmidi/win_midi.h +++ b/drivers/winmidi/win_midi.h @@ -33,14 +33,14 @@ #ifndef WIN_MIDI_H #define WIN_MIDI_H +#include "core/os/midi_driver.h" +#include "core/vector.h" + #include <stdio.h> #include <windows.h> #include <mmsystem.h> -#include "core/vector.h" -#include "os/midi_driver.h" - class MIDIDriverWinMidi : public MIDIDriver { Vector<HMIDIIN> connected_sources; diff --git a/drivers/xaudio2/SCsub b/drivers/xaudio2/SCsub index cb780a893b..3dca95b429 100644 --- a/drivers/xaudio2/SCsub +++ b/drivers/xaudio2/SCsub @@ -5,5 +5,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") env.Append(CXXFLAGS=['-DXAUDIO2_ENABLED']) env.Append(LINKFLAGS=['xaudio2_8.lib']) - -Export('env') diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp index a1002ef4f9..452a1105ca 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -30,8 +30,8 @@ #include "audio_driver_xaudio2.h" -#include "os/os.h" -#include "project_settings.h" +#include "core/os/os.h" +#include "core/project_settings.h" const char *AudioDriverXAudio2::get_name() const { return "XAudio2"; diff --git a/drivers/zlib/SCsub b/drivers/zlib/SCsub deleted file mode 100644 index 407deb5f6e..0000000000 --- a/drivers/zlib/SCsub +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -Import('env') - -# Not cloning the env, the includes need to be accessible for core/ - -# Thirdparty source files -# No check here as already done in drivers/SCsub -thirdparty_dir = "#thirdparty/zlib/" -thirdparty_sources = [ - "adler32.c", - "compress.c", - "crc32.c", - "deflate.c", - "infback.c", - "inffast.c", - "inflate.c", - "inftrees.c", - "trees.c", - "uncompr.c", - "zutil.c", -] -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -env.add_source_files(env.drivers_sources, thirdparty_sources) -env.Append(CPPPATH=[thirdparty_dir]) |