diff options
Diffstat (limited to 'drivers')
131 files changed, 11791 insertions, 4775 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index f9cfa3fb05..583973c025 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') @@ -16,7 +13,6 @@ SConscript('alsa/SCsub') SConscript('coreaudio/SCsub') SConscript('pulseaudio/SCsub') if (env["platform"] == "windows"): - SConscript("rtaudio/SCsub") SConscript("wasapi/SCsub") if env['xaudio2']: SConscript("xaudio2/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 50697b8834..42899c0f76 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -159,7 +159,7 @@ Error AudioDriverALSA::init() { } return err; -}; +} void AudioDriverALSA::thread_func(void *p_udata) { @@ -171,14 +171,14 @@ void AudioDriverALSA::thread_func(void *p_udata) { ad->start_counting_ticks(); if (!ad->active) { - for (unsigned int i = 0; i < ad->period_size * ad->channels; i++) { + for (uint64_t i = 0; i < ad->period_size * ad->channels; i++) { ad->samples_out.write[i] = 0; } } else { ad->audio_server_process(ad->period_size, ad->samples_in.ptrw()); - for (unsigned int i = 0; i < ad->period_size * ad->channels; i++) { + for (uint64_t i = 0; i < ad->period_size * ad->channels; i++) { ad->samples_out.write[i] = ad->samples_in[i] >> 16; } } @@ -232,25 +232,25 @@ void AudioDriverALSA::thread_func(void *p_udata) { ad->stop_counting_ticks(); ad->unlock(); - }; + } ad->thread_exited = true; -}; +} void AudioDriverALSA::start() { active = true; -}; +} int AudioDriverALSA::get_mix_rate() const { return mix_rate; -}; +} AudioDriver::SpeakerMode AudioDriverALSA::get_speaker_mode() const { return speaker_mode; -}; +} Array AudioDriverALSA::get_device_list() { @@ -302,14 +302,14 @@ void AudioDriverALSA::lock() { if (!thread || !mutex) return; mutex->lock(); -}; +} void AudioDriverALSA::unlock() { if (!thread || !mutex) return; mutex->unlock(); -}; +} void AudioDriverALSA::finish_device() { @@ -337,18 +337,15 @@ void AudioDriverALSA::finish() { finish_device(); } -AudioDriverALSA::AudioDriverALSA() { - - mutex = NULL; - thread = NULL; - pcm_handle = NULL; - - device_name = "Default"; - new_device = "Default"; -}; - -AudioDriverALSA::~AudioDriverALSA(){ +AudioDriverALSA::AudioDriverALSA() : + thread(NULL), + mutex(NULL), + pcm_handle(NULL), + device_name("Default"), + new_device("Default") { +} -}; +AudioDriverALSA::~AudioDriverALSA() { +} #endif diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index e2a2325cf3..0079ffb6d9 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/drivers/alsa/audio_driver_alsa.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ 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/midi_driver_alsamidi.cpp index 33ad7e3f17..aae0ae0216 100644 --- a/drivers/alsamidi/alsa_midi.cpp +++ b/drivers/alsamidi/midi_driver_alsamidi.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* alsa_midi.cpp */ +/* midi_driver_alsamidi.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -30,7 +30,7 @@ #ifdef ALSAMIDI_ENABLED -#include "alsa_midi.h" +#include "midi_driver_alsamidi.h" #include "core/os/os.h" #include "core/print_string.h" @@ -199,4 +199,4 @@ MIDIDriverALSAMidi::~MIDIDriverALSAMidi() { close(); } -#endif +#endif // ALSAMIDI_ENABLED diff --git a/drivers/alsamidi/alsa_midi.h b/drivers/alsamidi/midi_driver_alsamidi.h index 5741036166..b6956cc32f 100644 --- a/drivers/alsamidi/alsa_midi.h +++ b/drivers/alsamidi/midi_driver_alsamidi.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* alsa_midi.h */ +/* midi_driver_alsamidi.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -30,8 +30,8 @@ #ifdef ALSAMIDI_ENABLED -#ifndef ALSA_MIDI_H -#define ALSA_MIDI_H +#ifndef MIDI_DRIVER_ALSAMIDI_H +#define MIDI_DRIVER_ALSAMIDI_H #include "core/os/midi_driver.h" #include "core/os/mutex.h" @@ -65,5 +65,5 @@ public: virtual ~MIDIDriverALSAMidi(); }; -#endif -#endif +#endif // MIDI_DRIVER_ALSAMIDI_H +#endif // ALSAMIDI_ENABLED 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.cpp b/drivers/convex_decomp/b2d_decompose.cpp index 14456144a6..7b16b6e752 100644 --- a/drivers/convex_decomp/b2d_decompose.cpp +++ b/drivers/convex_decomp/b2d_decompose.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/convex_decomp/b2d_decompose.h b/drivers/convex_decomp/b2d_decompose.h index f6b08b957c..e79f692852 100644 --- a/drivers/convex_decomp/b2d_decompose.h +++ b/drivers/convex_decomp/b2d_decompose.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ 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 09e50e4aaa..3b06c47244 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -95,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; @@ -123,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)); @@ -158,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); @@ -175,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"); @@ -189,15 +156,12 @@ 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); + if (GLOBAL_GET("audio/enable_audio_input")) { + return capture_init(); + } return OK; } @@ -265,19 +229,19 @@ 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; - ad->input_buffer_write(sample); + ad->capture_buffer_write(sample); if (ad->capture_channels == 1) { - // In case input device is single channel convert it to Stereo - ad->input_buffer_write(sample); + // In case capture device is single channel convert it to Stereo + ad->capture_buffer_write(sample); } } } else { - ERR_PRINT(("AudioUnitRender failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioUnitRender failed, code: " + itos(result)); } ad->unlock(); @@ -289,7 +253,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; } @@ -300,7 +264,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; } @@ -332,6 +296,8 @@ bool AudioDriverCoreAudio::try_lock() { } void AudioDriverCoreAudio::finish() { + capture_finish(); + if (audio_unit) { OSStatus result; @@ -375,6 +341,7 @@ void AudioDriverCoreAudio::finish() { ERR_PRINT("AudioComponentInstanceDispose failed"); } + audio_unit = NULL; unlock(); } @@ -384,20 +351,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() { + + capture_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; } @@ -531,12 +638,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 capture to keep synchronisation. + capture_position = 0; + capture_size = 0; + } } } @@ -578,21 +687,18 @@ String AudioDriverCoreAudio::capture_get_device() { #endif -AudioDriverCoreAudio::AudioDriverCoreAudio() { - audio_unit = NULL; - active = false; - mutex = NULL; - - mix_rate = 0; - channels = 2; - capture_channels = 2; - - buffer_frames = 0; - +AudioDriverCoreAudio::AudioDriverCoreAudio() : + audio_unit(NULL), + input_unit(NULL), + active(false), + mutex(NULL), + device_name("Default"), + capture_device_name("Default"), + mix_rate(0), + channels(2), + capture_channels(2), + buffer_frames(0) { samples_in.clear(); - - device_name = "Default"; - capture_device_name = "Default"; } AudioDriverCoreAudio::~AudioDriverCoreAudio(){}; diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index d3f7c8d596..f37d781cb6 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -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/midi_driver_coremidi.cpp index e8106c4543..7a92ac0702 100644 --- a/drivers/coremidi/core_midi.cpp +++ b/drivers/coremidi/midi_driver_coremidi.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* core_midi.cpp */ +/* midi_driver_coremidi.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -30,7 +30,7 @@ #ifdef COREMIDI_ENABLED -#include "core_midi.h" +#include "midi_driver_coremidi.h" #include "core/print_string.h" @@ -51,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; } @@ -65,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); } @@ -112,14 +112,12 @@ PoolStringArray MIDIDriverCoreMidi::get_connected_inputs() { return list; } -MIDIDriverCoreMidi::MIDIDriverCoreMidi() { - - client = 0; +MIDIDriverCoreMidi::MIDIDriverCoreMidi() : + client(0) { } MIDIDriverCoreMidi::~MIDIDriverCoreMidi() { - close(); } -#endif +#endif // COREMIDI_ENABLED diff --git a/drivers/coremidi/core_midi.h b/drivers/coremidi/midi_driver_coremidi.h index ea6b0fcb06..23c2a19812 100644 --- a/drivers/coremidi/core_midi.h +++ b/drivers/coremidi/midi_driver_coremidi.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* core_midi.h */ +/* midi_driver_coremidi.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -30,8 +30,8 @@ #ifdef COREMIDI_ENABLED -#ifndef CORE_MIDI_H -#define CORE_MIDI_H +#ifndef MIDI_DRIVER_COREMIDI_H +#define MIDI_DRIVER_COREMIDI_H #include "core/os/midi_driver.h" #include "core/vector.h" @@ -58,5 +58,5 @@ public: virtual ~MIDIDriverCoreMidi(); }; -#endif -#endif +#endif // MIDI_DRIVER_COREMIDI_H +#endif // COREMIDI_ENABLED diff --git a/drivers/dummy/audio_driver_dummy.h b/drivers/dummy/audio_driver_dummy.h index b3f0fcee07..4f4d7f9bc4 100644 --- a/drivers/dummy/audio_driver_dummy.h +++ b/drivers/dummy/audio_driver_dummy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 126f23feeb..8d5cf2ebea 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -56,14 +56,17 @@ public: void environment_set_background(RID p_env, VS::EnvironmentBG p_bg) {} void environment_set_sky(RID p_env, RID p_sky) {} void environment_set_sky_custom_fov(RID p_env, float p_scale) {} + void environment_set_sky_orientation(RID p_env, const Basis &p_orientation) {} void environment_set_bg_color(RID p_env, const Color &p_color) {} void environment_set_bg_energy(RID p_env, float p_energy) {} void environment_set_canvas_max_layer(RID p_env, int p_max_layer) {} void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0) {} + void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id){}; void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} - void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) {} + void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {} + void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {} void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) {} @@ -74,7 +77,7 @@ public: void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {} - void 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) {} + void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {} void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {} bool is_environment(RID p_env) { return false; } @@ -178,8 +181,8 @@ public: DummyTexture *t = texture_owner.get(p_texture); ERR_FAIL_COND(!t); + ERR_FAIL_COND_MSG(p_image.is_null(), "It's not a reference to a valid Image object."); ERR_FAIL_COND(t->format != p_image->get_format()); - ERR_FAIL_COND(p_image.is_null()); ERR_FAIL_COND(src_w <= 0 || src_h <= 0); ERR_FAIL_COND(src_x < 0 || src_y < 0 || src_x + src_w > p_image->get_width() || src_y + src_h > p_image->get_height()); ERR_FAIL_COND(dst_x < 0 || dst_y < 0 || dst_x + src_w > t->width || dst_y + src_h > t->height); @@ -214,6 +217,7 @@ public: uint32_t texture_get_height(RID p_texture) const { return 0; } uint32_t texture_get_depth(RID p_texture) const { return 0; } void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) {} + void texture_bind(RID p_texture, uint32_t p_texture_no) {} void texture_set_path(RID p_texture, const String &p_path) { DummyTexture *t = texture_owner.getornull(p_texture); @@ -239,6 +243,7 @@ public: void textures_keep_original(bool p_enable) {} void texture_set_proxy(RID p_proxy, RID p_base) {} + virtual Size2 texture_size_with_proxy(RID p_texture) const { return Size2(); } void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {} /* SKY API */ @@ -458,6 +463,7 @@ public: RID skeleton_create() { return RID(); } void skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton = false) {} void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {} + void skeleton_set_world_transform(RID p_skeleton, bool p_enable, const Transform &p_world_transform) {} int skeleton_get_bone_count(RID p_skeleton) const { return 0; } void skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) {} Transform skeleton_bone_get_transform(RID p_skeleton, int p_bone) const { return Transform(); } @@ -480,6 +486,7 @@ public: void light_set_negative(RID p_light, bool p_enable) {} void light_set_cull_mask(RID p_light, uint32_t p_mask) {} void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {} + void light_set_use_gi(RID p_light, bool p_enabled) {} void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) {} void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail) {} @@ -499,6 +506,7 @@ public: AABB light_get_aabb(RID p_light) const { return AABB(); } float light_get_param(RID p_light, VS::LightParam p_param) { return 0.0; } Color light_get_color(RID p_light) { return Color(); } + bool light_get_use_gi(RID p_light) { return false; } uint64_t light_get_version(RID p_light) const { return 0; } /* PROBE API */ @@ -517,6 +525,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; } @@ -583,22 +592,12 @@ public: SelfList<RasterizerScene::InstanceBase>::List instance_list; - _FORCE_INLINE_ void instance_change_notify() { + _FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) { SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); while (instances) { - instances->self()->base_changed(); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_material_change_notify() { - - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - - instances->self()->base_material_changed(); + instances->self()->base_changed(p_aabb, p_materials); instances = instances->next(); } } @@ -690,11 +689,15 @@ public: int particles_get_draw_passes(RID p_particles) const { return 0; } RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { return RID(); } + virtual bool particles_is_inactive(RID p_particles) const { return false; } + /* RENDER TARGET */ RID render_target_create() { return RID(); } + void render_target_set_position(RID p_render_target, int p_x, int p_y) {} void render_target_set_size(RID p_render_target, int p_width, int p_height) {} RID render_target_get_texture(RID p_render_target) const { return RID(); } + void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) {} void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) {} bool render_target_was_used(RID p_render_target) { return false; } void render_target_clear_used(RID p_render_target) {} @@ -779,14 +782,15 @@ public: RasterizerCanvas *get_canvas() { return &canvas; } RasterizerScene *get_scene() { return &scene; } - void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) {} + void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true) {} void initialize() {} void begin_frame(double frame_step) {} void set_current_render_target(RID p_render_target) {} - void restore_render_target() {} + void restore_render_target(bool p_3d_was_drawn) {} 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() {} @@ -802,6 +806,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 8153fbd10b..88d11fef2c 100644 --- a/drivers/dummy/texture_loader_dummy.cpp +++ b/drivers/dummy/texture_loader_dummy.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* texture_loader_dummy.cpp */ +/* texture_loader_dummy.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/dummy/texture_loader_dummy.h b/drivers/dummy/texture_loader_dummy.h index f0a355ec12..0bc7fa226b 100644 --- a/drivers/dummy/texture_loader_dummy.h +++ b/drivers/dummy/texture_loader_dummy.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* texture_loader_dummy.h */ +/* texture_loader_dummy.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub index 4d66a9f9f1..b9f0ea2254 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.Prepend(CPPPATH=[thirdparty_dir]) - env.Append(CPPFLAGS=['-DGLAD_ENABLED']) - env.Append(CPPFLAGS=['-DGLES_OVER_GL']) + env.Append(CPPDEFINES=['GLAD_ENABLED']) + env.Append(CPPDEFINES=['GLES_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 deleted file mode 100644 index 37f334454b..0000000000 --- a/drivers/gl_context/context_gl.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************/ -/* context_gl.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 CONTEXT_GL_H -#define CONTEXT_GL_H - -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) - -#include "core/typedefs.h" - -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - -class ContextGL { - - static ContextGL *singleton; - -public: - static ContextGL *get_singleton(); - - virtual void release_current() = 0; - - virtual void make_current() = 0; - - virtual void swap_buffers() = 0; - - virtual Error initialize() = 0; - - virtual void set_use_vsync(bool p_use) = 0; - virtual bool is_using_vsync() const = 0; - - ContextGL(); - ~ContextGL(); -}; - -#endif - -#endif 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 4ae4441462..6be48a4c58 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -67,22 +67,75 @@ void RasterizerCanvasGLES2::_set_uniforms() { state.canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); } + + if (state.using_skeleton) { + state.canvas_shader.set_uniform(CanvasShaderGLES2::SKELETON_TRANSFORM, state.skeleton_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES2::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse); + state.canvas_shader.set_uniform(CanvasShaderGLES2::SKELETON_TEXTURE_SIZE, state.skeleton_texture_size); + } + + if (state.using_light) { + + Light *light = state.using_light; + state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX, light->light_shader_xform); + Transform2D basis_inverse = light->light_shader_xform.affine_inverse().orthonormalized(); + basis_inverse[2] = Vector2(); + state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_MATRIX_INVERSE, basis_inverse); + state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_LOCAL_MATRIX, light->xform_cache.affine_inverse()); + state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_COLOR, light->color * light->energy); + state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_POS, light->light_shader_pos); + state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_HEIGHT, light->height); + state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_OUTSIDE_ALPHA, light->mode == VS::CANVAS_LIGHT_MODE_MASK ? 1.0 : 0.0); + + if (state.using_shadow) { + RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(light->shadow_buffer); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); + glBindTexture(GL_TEXTURE_2D, cls->distance); + state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX, light->shadow_matrix_cache); + state.canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_SHADOW_COLOR, light->shadow_color); + + state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOWPIXEL_SIZE, (1.0 / light->shadow_buffer_size) * (1.0 + light->shadow_smooth)); + if (light->radius_cache == 0) { + state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_GRADIENT, 0.0); + } else { + state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_GRADIENT, light->shadow_gradient_length / (light->radius_cache * 1.1)); + } + state.canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_DISTANCE_MULT, light->radius_cache * 1.1); + + /*canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_MATRIX,light->shadow_matrix_cache); + canvas_shader.set_uniform(CanvasShaderGLES2::SHADOW_ESM_MULTIPLIER,light->shadow_esm_mult); + canvas_shader.set_uniform(CanvasShaderGLES2::LIGHT_SHADOW_COLOR,light->shadow_color);*/ + } + } } void RasterizerCanvasGLES2::canvas_begin() { state.canvas_shader.bind(); + state.using_transparent_rt = false; + int viewport_x, viewport_y, viewport_width, viewport_height; + if (storage->frame.current_rt) { glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); - glColorMask(1, 1, 1, 1); + state.using_transparent_rt = storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; + + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + // set Viewport and Scissor when rendering directly to screen + viewport_width = storage->frame.current_rt->width; + viewport_height = storage->frame.current_rt->height; + viewport_x = storage->frame.current_rt->x; + viewport_y = OS::get_singleton()->get_window_size().height - viewport_height - storage->frame.current_rt->y; + glScissor(viewport_x, viewport_y, viewport_width, viewport_height); + glViewport(viewport_x, viewport_y, viewport_width, viewport_height); + glEnable(GL_SCISSOR_TEST); + } } if (storage->frame.clear_request) { - glColorMask(true, true, true, true); glClearColor(storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, - storage->frame.clear_request_color.a); + state.using_transparent_rt ? storage->frame.clear_request_color.a : 1.0); glClear(GL_COLOR_BUFFER_BIT); storage->frame.clear_request = false; } @@ -139,8 +192,18 @@ void RasterizerCanvasGLES2::canvas_end() { glDisableVertexAttribArray(i); } + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + //reset viewport to full window size + int viewport_width = OS::get_singleton()->get_window_size().width; + int viewport_height = OS::get_singleton()->get_window_size().height; + glViewport(0, 0, viewport_width, viewport_height); + glScissor(0, 0, viewport_width, viewport_height); + } + state.using_texture_rect = false; + state.using_skeleton = false; state.using_ninepatch = false; + state.using_transparent_rt = false; } RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(const RID &p_texture, const RID &p_normal_map) { @@ -160,12 +223,12 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con } else { - texture = texture->get_ptr(); - if (texture->redraw_if_visible) { VisualServerRaster::redraw_request(); } + texture = texture->get_ptr(); + if (texture->render_target) { texture->render_target->used_in_frame = true; } @@ -186,13 +249,46 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); } - return tex_return; -} + if (p_normal_map == state.current_normal) { + //do none + state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, state.current_normal.is_valid()); + + } else if (p_normal_map.is_valid()) { + + RasterizerStorageGLES2::Texture *normal_map = storage->texture_owner.getornull(p_normal_map); + + if (!normal_map) { + state.current_normal = RID(); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); + glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); + state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, false); + + } else { -void RasterizerCanvasGLES2::_set_texture_rect_mode(bool p_enable, bool p_ninepatch) { + if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies + VisualServerRaster::redraw_request(); + } + + normal_map = normal_map->get_ptr(); + + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); + glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); + state.current_normal = p_normal_map; + state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, true); + } + + } else { + + state.current_normal = RID(); + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2); + glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex); + state.canvas_shader.set_uniform(CanvasShaderGLES2::USE_DEFAULT_NORMAL, false); + } + + return tex_return; } -void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor) { +void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights, const int *p_bones) { glBindBuffer(GL_ARRAY_BUFFER, data.polygon_buffer); @@ -213,23 +309,47 @@ void RasterizerCanvasGLES2::_draw_polygon(const int *p_indices, int p_index_coun } else { glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Color) * p_vertex_count; } if (p_uvs) { glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Vector2) * p_vertex_count; } else { glDisableVertexAttribArray(VS::ARRAY_TEX_UV); } - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); - glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); + if (p_weights && p_bones) { + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights); + glEnableVertexAttribArray(VS::ARRAY_WEIGHTS); + glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs += sizeof(float) * 4 * p_vertex_count; - glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); + glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones); + glEnableVertexAttribArray(VS::ARRAY_BONES); + glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, GL_FALSE, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); + buffer_ofs += sizeof(int) * 4 * p_vertex_count; + + } else { + glDisableVertexAttribArray(VS::ARRAY_WEIGHTS); + glDisableVertexAttribArray(VS::ARRAY_BONES); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); + if (storage->config.support_32_bits_indices) { //should check for + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(int) * p_index_count, p_indices); + glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_INT, 0); + } else { + uint16_t *index16 = (uint16_t *)alloca(sizeof(uint16_t) * p_index_count); + for (int i = 0; i < p_index_count; i++) { + index16[i] = uint16_t(p_indices[i]); + } + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(uint16_t) * p_index_count, index16); + glDrawElements(GL_TRIANGLES, p_index_count, GL_UNSIGNED_SHORT, 0); + } glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); @@ -243,7 +363,7 @@ void RasterizerCanvasGLES2::_draw_generic(GLuint p_primitive, int p_vertex_count glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector2) * p_vertex_count, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), (uint8_t *)0); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), NULL); buffer_ofs += sizeof(Vector2) * p_vertex_count; if (p_singlecolor) { @@ -256,14 +376,14 @@ void RasterizerCanvasGLES2::_draw_generic(GLuint p_primitive, int p_vertex_count } else { glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Color) * p_vertex_count; } if (p_uvs) { glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); } else { glDisableVertexAttribArray(VS::ARRAY_TEX_UV); } @@ -320,12 +440,12 @@ void RasterizerCanvasGLES2::_draw_gui_primitive(int p_points, const Vector2 *p_v glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), NULL); if (p_colors) { - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), (uint8_t *)0 + color_offset * sizeof(float)); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(color_offset * sizeof(float))); glEnableVertexAttribArray(VS::ARRAY_COLOR); } if (p_uvs) { - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), (uint8_t *)0 + uv_offset * sizeof(float)); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride * sizeof(float), CAST_INT_TO_UCHAR_PTR(uv_offset * sizeof(float))); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); } @@ -334,6 +454,16 @@ void RasterizerCanvasGLES2::_draw_gui_primitive(int p_points, const Vector2 *p_v glBindBuffer(GL_ARRAY_BUFFER, 0); } +static const GLenum gl_primitive[] = { + GL_POINTS, + GL_LINES, + GL_LINE_STRIP, + GL_LINE_LOOP, + GL_TRIANGLES, + GL_TRIANGLE_STRIP, + GL_TRIANGLE_FAN +}; + void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) { int command_count = p_item->commands.size(); @@ -350,7 +480,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Item::CommandLine *line = static_cast<Item::CommandLine *>(command); state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); if (state.canvas_shader.bind()) { _set_uniforms(); state.canvas_shader.use_material((void *)p_material); @@ -369,7 +498,16 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Vector2(line->to.x, line->to.y) }; +#ifdef GLES_OVER_GL + if (line->antialiased) + glEnable(GL_LINE_SMOOTH); +#endif _draw_gui_primitive(2, verts, NULL, NULL); + +#ifdef GLES_OVER_GL + if (line->antialiased) + glDisable(GL_LINE_SMOOTH); +#endif } else { Vector2 t = (line->from - line->to).normalized().tangent() * line->width * 0.5; @@ -381,6 +519,19 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur }; _draw_gui_primitive(4, verts, NULL, NULL); +#ifdef GLES_OVER_GL + if (line->antialiased) { + glEnable(GL_LINE_SMOOTH); + for (int j = 0; j < 4; j++) { + Vector2 vertsl[2] = { + verts[j], + verts[(j + 1) % 4], + }; + _draw_gui_primitive(2, vertsl, NULL, NULL); + } + glDisable(GL_LINE_SMOOTH); + } +#endif } } break; @@ -391,84 +542,190 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur glDisableVertexAttribArray(VS::ARRAY_COLOR); glVertexAttrib4fv(VS::ARRAY_COLOR, r->modulate.components); - _bind_quad_buffer(); + bool can_tile = true; + if (r->texture.is_valid() && r->flags & CANVAS_RECT_TILE && !storage->config.support_npot_repeat_mipmap) { + // workaround for when setting tiling does not work due to hardware limitation - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); - if (state.canvas_shader.bind()) { - _set_uniforms(); - state.canvas_shader.use_material((void *)p_material); + RasterizerStorageGLES2::Texture *texture = storage->texture_owner.getornull(r->texture); + + if (texture) { + + texture = texture->get_ptr(); + + if (next_power_of_2(texture->alloc_width) != (unsigned int)texture->alloc_width && next_power_of_2(texture->alloc_height) != (unsigned int)texture->alloc_height) { + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_FORCE_REPEAT, true); + can_tile = false; + } + } } - RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map); + // On some widespread Nvidia cards, the normal draw method can produce some + // flickering in draw_rect and especially TileMap rendering (tiles randomly flicker). + // See GH-9913. + // To work it around, we use a simpler draw method which does not flicker, but gives + // a non negligible performance hit, so it's opt-in (GH-24466). + if (use_nvidia_rect_workaround) { + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } - if (!tex) { - Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); + Vector2 points[4] = { + r->rect.position, + r->rect.position + Vector2(r->rect.size.x, 0.0), + r->rect.position + r->rect.size, + r->rect.position + Vector2(0.0, r->rect.size.y), + }; - if (dst_rect.size.width < 0) { - dst_rect.position.x += dst_rect.size.width; - dst_rect.size.width *= -1; + if (r->rect.size.x < 0) { + SWAP(points[0], points[1]); + SWAP(points[2], points[3]); } - if (dst_rect.size.height < 0) { - dst_rect.position.y += dst_rect.size.height; - dst_rect.size.height *= -1; + if (r->rect.size.y < 0) { + SWAP(points[0], points[3]); + SWAP(points[1], points[2]); } - state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(0, 0, 1, 1)); + RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(r->texture, r->normal_map); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); - } else { + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); - bool untile = false; + Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); - if (r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - untile = true; - } + Vector2 uvs[4] = { + src_rect.position, + src_rect.position + Vector2(src_rect.size.x, 0.0), + src_rect.position + src_rect.size, + src_rect.position + Vector2(0.0, src_rect.size.y), + }; + + if (r->flags & CANVAS_RECT_TRANSPOSE) { + SWAP(uvs[1], uvs[3]); + } - Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); - Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); + if (r->flags & CANVAS_RECT_FLIP_H) { + SWAP(uvs[0], uvs[1]); + SWAP(uvs[2], uvs[3]); + } + if (r->flags & CANVAS_RECT_FLIP_V) { + SWAP(uvs[0], uvs[3]); + SWAP(uvs[1], uvs[2]); + } - Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - if (dst_rect.size.width < 0) { - dst_rect.position.x += dst_rect.size.width; - dst_rect.size.width *= -1; - } - if (dst_rect.size.height < 0) { - dst_rect.position.y += dst_rect.size.height; - dst_rect.size.height *= -1; - } + bool untile = false; - if (r->flags & CANVAS_RECT_FLIP_H) { - src_rect.size.x *= -1; - } + if (can_tile && r->flags & CANVAS_RECT_TILE && !(texture->flags & VS::TEXTURE_FLAG_REPEAT)) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + untile = true; + } - if (r->flags & CANVAS_RECT_FLIP_V) { - src_rect.size.y *= -1; + _draw_gui_primitive(4, points, NULL, uvs); + + if (untile) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + } else { + static const Vector2 uvs[4] = { + Vector2(0.0, 0.0), + Vector2(0.0, 1.0), + Vector2(1.0, 1.0), + Vector2(1.0, 0.0), + }; + + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, Vector2()); + _draw_gui_primitive(4, points, NULL, uvs); } - if (r->flags & CANVAS_RECT_TRANSPOSE) { - dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform + } else { + // This branch is better for performance, but can produce flicker on Nvidia, see above comment. + _bind_quad_buffer(); + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); } - state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); + RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map); + + if (!tex) { + Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); + + if (dst_rect.size.width < 0) { + dst_rect.position.x += dst_rect.size.width; + dst_rect.size.width *= -1; + } + if (dst_rect.size.height < 0) { + dst_rect.position.y += dst_rect.size.height; + dst_rect.size.height *= -1; + } + + state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(0, 0, 1, 1)); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } else { + + bool untile = false; + + if (can_tile && r->flags & CANVAS_RECT_TILE && !(tex->flags & VS::TEXTURE_FLAG_REPEAT)) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + untile = true; + } + + Size2 texpixel_size(1.0 / tex->width, 1.0 / tex->height); + Rect2 src_rect = (r->flags & CANVAS_RECT_REGION) ? Rect2(r->source.position * texpixel_size, r->source.size * texpixel_size) : Rect2(0, 0, 1, 1); + + Rect2 dst_rect = Rect2(r->rect.position, r->rect.size); + + if (dst_rect.size.width < 0) { + dst_rect.position.x += dst_rect.size.width; + dst_rect.size.width *= -1; + } + if (dst_rect.size.height < 0) { + dst_rect.position.y += dst_rect.size.height; + dst_rect.size.height *= -1; + } + + if (r->flags & CANVAS_RECT_FLIP_H) { + src_rect.size.x *= -1; + } - state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); + if (r->flags & CANVAS_RECT_FLIP_V) { + src_rect.size.y *= -1; + } + + if (r->flags & CANVAS_RECT_TRANSPOSE) { + dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform + } + + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); - glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + state.canvas_shader.set_uniform(CanvasShaderGLES2::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); + state.canvas_shader.set_uniform(CanvasShaderGLES2::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); - if (untile) { - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + if (untile) { + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_FORCE_REPEAT, false); } break; @@ -477,7 +734,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Item::CommandNinePatch *np = static_cast<Item::CommandNinePatch *>(command); state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); if (state.canvas_shader.bind()) { _set_uniforms(); state.canvas_shader.use_material((void *)p_material); @@ -627,7 +883,7 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), NULL); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (uint8_t *)0 + (sizeof(float) * 2)); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, 4 * sizeof(float), CAST_INT_TO_UCHAR_PTR((sizeof(float) * 2))); glDrawElements(GL_TRIANGLES, 18 * 3 - (np->draw_center ? 0 : 6), GL_UNSIGNED_BYTE, NULL); @@ -641,7 +897,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Item::CommandCircle *circle = static_cast<Item::CommandCircle *>(command); state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); if (state.canvas_shader.bind()) { _set_uniforms(); @@ -655,11 +910,11 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur int indices[num_points * 3]; - for (int i = 0; i < num_points; i++) { - points[i] = circle->pos + Vector2(Math::sin(i * Math_PI * 2.0 / num_points), Math::cos(i * Math_PI * 2.0 / num_points)) * circle->radius; - indices[i * 3 + 0] = i; - indices[i * 3 + 1] = (i + 1) % num_points; - indices[i * 3 + 2] = num_points; + for (int j = 0; j < num_points; j++) { + points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / num_points), Math::cos(j * Math_PI * 2.0 / num_points)) * circle->radius; + indices[j * 3 + 0] = j; + indices[j * 3 + 1] = (j + 1) % num_points; + indices[j * 3 + 2] = num_points; } _bind_canvas_texture(RID(), RID()); @@ -672,7 +927,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Item::CommandPolygon *polygon = static_cast<Item::CommandPolygon *>(command); state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); if (state.canvas_shader.bind()) { _set_uniforms(); @@ -686,14 +940,205 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); } - _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); + _draw_polygon(polygon->indices.ptr(), polygon->count, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1, polygon->weights.ptr(), polygon->bones.ptr()); +#ifdef GLES_OVER_GL + if (polygon->antialiased) { + glEnable(GL_LINE_SMOOTH); + _draw_generic(GL_LINE_LOOP, polygon->points.size(), polygon->points.ptr(), polygon->uvs.ptr(), polygon->colors.ptr(), polygon->colors.size() == 1); + glDisable(GL_LINE_SMOOTH); + } +#endif } break; + case Item::Command::TYPE_MESH: { + + Item::CommandMesh *mesh = static_cast<Item::CommandMesh *>(command); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(mesh->texture, mesh->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + RasterizerStorageGLES2::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); + if (mesh_data) { + + for (int j = 0; j < mesh_data->surfaces.size(); j++) { + RasterizerStorageGLES2::Surface *s = mesh_data->surfaces[j]; + // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing + + glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); + + if (s->index_array_len > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); + } + + for (int k = 0; k < VS::ARRAY_MAX - 1; k++) { + if (s->attribs[k].enabled) { + glEnableVertexAttribArray(k); + glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset)); + } else { + glDisableVertexAttribArray(k); + switch (k) { + 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: { + } + } + } + } + + 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); + } + } + + for (int j = 1; j < VS::ARRAY_MAX - 1; j++) { + glDisableVertexAttribArray(j); + } + } + + } break; + case Item::Command::TYPE_MULTIMESH: { + Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(command); + + RasterizerStorageGLES2::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh); + + if (!multi_mesh) + break; + + RasterizerStorageGLES2::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh); + + if (!mesh_data) + break; + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != VS::MULTIMESH_CUSTOM_DATA_NONE); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCING, true); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); + + if (state.canvas_shader.bind()) { + _set_uniforms(); + state.canvas_shader.use_material((void *)p_material); + } + + RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map); + + if (texture) { + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); + state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size); + } + + //reset shader and force rebind + + int amount = MIN(multi_mesh->size, multi_mesh->visible_instances); + + if (amount == -1) { + amount = multi_mesh->size; + } + + int stride = multi_mesh->color_floats + multi_mesh->custom_data_floats + multi_mesh->xform_floats; + + int color_ofs = multi_mesh->xform_floats; + int custom_data_ofs = color_ofs + multi_mesh->color_floats; + + // drawing + + const float *base_buffer = multi_mesh->data.ptr(); + + for (int j = 0; j < mesh_data->surfaces.size(); j++) { + RasterizerStorageGLES2::Surface *s = mesh_data->surfaces[j]; + // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing + + //bind buffers for mesh surface + glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); + + if (s->index_array_len > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id); + } + + for (int k = 0; k < VS::ARRAY_MAX - 1; k++) { + if (s->attribs[k].enabled) { + glEnableVertexAttribArray(k); + glVertexAttribPointer(s->attribs[k].index, s->attribs[k].size, s->attribs[k].type, s->attribs[k].normalized, s->attribs[k].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[k].offset)); + } else { + glDisableVertexAttribArray(k); + switch (k) { + 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: { + } + } + } + } + + for (int k = 0; k < amount; k++) { + const float *buffer = base_buffer + k * stride; + { + + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]); + if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) { + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]); + } else { + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 2, 0.0, 0.0, 1.0, 0.0); + } + } + + if (multi_mesh->color_floats) { + if (multi_mesh->color_format == VS::MULTIMESH_COLOR_8BIT) { + uint8_t *color_data = (uint8_t *)(buffer + color_ofs); + 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(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); + } + } else { + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, 1.0, 1.0, 1.0, 1.0); + } + + if (multi_mesh->custom_data_floats) { + 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) { + 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); + } + } + } + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCE_CUSTOM, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_INSTANCING, false); + + } break; case Item::Command::TYPE_POLYLINE: { Item::CommandPolyLine *pline = static_cast<Item::CommandPolyLine *>(command); state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); if (state.canvas_shader.bind()) { _set_uniforms(); @@ -704,7 +1149,22 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur if (pline->triangles.size()) { _draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1); +#ifdef GLES_OVER_GL + glEnable(GL_LINE_SMOOTH); + if (pline->multiline) { + //needs to be different + } else { + _draw_generic(GL_LINE_LOOP, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); + } + glDisable(GL_LINE_SMOOTH); +#endif } else { + +#ifdef GLES_OVER_GL + if (pline->antialiased) + glEnable(GL_LINE_SMOOTH); +#endif + if (pline->multiline) { int todo = pline->lines.size() / 2; int max_per_call = data.polygon_buffer_size / (sizeof(real_t) * 4); @@ -719,6 +1179,11 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur } else { _draw_generic(GL_LINES, pline->lines.size(), pline->lines.ptr(), NULL, pline->line_colors.ptr(), pline->line_colors.size() == 1); } + +#ifdef GLES_OVER_GL + if (pline->antialiased) + glDisable(GL_LINE_SMOOTH); +#endif } } break; @@ -726,7 +1191,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur Item::CommandPrimitive *primitive = static_cast<Item::CommandPrimitive *>(command); state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false); - state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true); if (state.canvas_shader.bind()) { _set_uniforms(); @@ -798,9 +1262,73 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur } } +void RasterizerCanvasGLES2::_copy_screen(const Rect2 &p_rect) { + + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + ERR_PRINT_ONCE("Cannot use screen texture copying in render target set to render direct to screen."); + return; + } + + ERR_FAIL_COND_MSG(storage->frame.current_rt->copy_screen_effect.color == 0, "Can't use screen texture copying in a render target configured without copy buffers."); + + glDisable(GL_BLEND); + + Vector2 wh(storage->frame.current_rt->width, storage->frame.current_rt->height); + + Color copy_section(p_rect.position.x / wh.x, p_rect.position.y / wh.y, p_rect.size.x / wh.x, p_rect.size.y / wh.y); + + if (p_rect != Rect2()) { + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, true); + } + + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, !state.using_transparent_rt); + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->copy_screen_effect.fbo); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + + storage->shaders.copy.bind(); + storage->shaders.copy.set_uniform(CopyShaderGLES2::COPY_SECTION, copy_section); + + const Vector2 vertpos[4] = { + Vector2(-1, -1), + Vector2(-1, 1), + Vector2(1, 1), + Vector2(1, -1), + }; + + const Vector2 uvpos[4] = { + Vector2(0, 0), + Vector2(0, 1), + Vector2(1, 1), + Vector2(1, 0) + }; + + const int indexpos[6] = { + 0, 1, 2, + 2, 3, 0 + }; + + _draw_polygon(indexpos, 6, 4, vertpos, uvpos, NULL, false); + + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, false); + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //back to front + glEnable(GL_BLEND); +} + void RasterizerCanvasGLES2::_copy_texscreen(const Rect2 &p_rect) { - // This isn't really working yet, so disabling for now. + state.canvas_texscreen_used = true; + + _copy_screen(p_rect); + + // back to canvas, force rebind + state.using_texture_rect = false; + state.canvas_shader.bind(); + _bind_canvas_texture(state.current_tex, state.current_normal); + _set_uniforms(); } void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) { @@ -810,12 +1338,13 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons RasterizerStorageGLES2::Shader *shader_cache = NULL; bool rebind_shader = true; - - Size2 rt_size = Size2(storage->frame.current_rt->width, storage->frame.current_rt->height); + bool prev_use_skeleton = false; + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, false); state.current_tex = RID(); state.current_tex_ptr = NULL; state.current_normal = RID(); + state.canvas_texscreen_used = false; glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); @@ -853,6 +1382,37 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons } } + RasterizerStorageGLES2::Skeleton *skeleton = NULL; + + { + //skeleton handling + if (ci->skeleton.is_valid() && storage->skeleton_owner.owns(ci->skeleton)) { + skeleton = storage->skeleton_owner.get(ci->skeleton); + if (!skeleton->use_2d) { + skeleton = NULL; + } else { + state.skeleton_transform = p_base_transform * skeleton->base_transform_2d; + state.skeleton_transform_inverse = state.skeleton_transform.affine_inverse(); + state.skeleton_texture_size = Vector2(skeleton->size * 2, 0); + } + } + + bool use_skeleton = skeleton != NULL; + if (prev_use_skeleton != use_skeleton) { + rebind_shader = true; + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, use_skeleton); + prev_use_skeleton = use_skeleton; + } + + if (skeleton) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); + glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); + state.using_skeleton = true; + } else { + state.using_skeleton = false; + } + } + Item *material_owner = ci->material_owner ? ci->material_owner : ci; RID material = material_owner->material; @@ -872,7 +1432,18 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons if (shader_ptr) { if (shader_ptr->canvas_item.uses_screen_texture) { - _copy_texscreen(Rect2()); + if (!state.canvas_texscreen_used) { + //copy if not copied before + _copy_texscreen(Rect2()); + + // blend mode will have been enabled so make sure we disable it again later on + //last_blend_mode = last_blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_DISABLED ? last_blend_mode : -1; + } + + if (storage->frame.current_rt->copy_screen_effect.color) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); + } } if (shader_ptr != shader_cache) { @@ -917,12 +1488,20 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons continue; } - t = t->get_ptr(); - if (t->redraw_if_visible) { VisualServerRaster::redraw_request(); } + t = t->get_ptr(); + +#ifdef TOOLS_ENABLED + if (t->detect_normal && texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL) { + t->detect_normal(t->detect_normal_ud); + } +#endif + if (t->render_target) + t->render_target->used_in_frame = true; + glBindTexture(t->target, t->tex_id); } @@ -940,7 +1519,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons } int blend_mode = shader_cache ? shader_cache->canvas_item.blend_mode : RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX; - bool unshaded = (shader_cache && blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX); + bool unshaded = shader_cache && (shader_cache->canvas_item.light_mode == RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_UNSHADED || (blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX && blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA)); bool reclip = false; if (last_blend_mode != blend_mode) { @@ -952,28 +1531,44 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons 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); + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); } } break; case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_ADD: { glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + } } break; case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_SUB: { glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); - glBlendFunc(GL_SRC_ALPHA, GL_ONE); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_SRC_ALPHA, GL_ONE); + } else { + glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE, GL_ZERO, GL_ONE); + } } break; case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MUL: { glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_DST_COLOR, GL_ZERO); + 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); + } } break; case RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA: { glBlendEquation(GL_FUNC_ADD); - glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + } else { + glBlendFuncSeparate(GL_ONE, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ONE); + } } break; } } @@ -985,10 +1580,135 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons _set_uniforms(); - _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr); + if (unshaded || (state.uniforms.final_modulate.a > 0.001 && (!shader_cache || shader_cache->canvas_item.light_mode != RasterizerStorageGLES2::Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY) && !ci->light_masked)) + _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr); rebind_shader = true; // hacked in for now. + if ((blend_mode == RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX || blend_mode == RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_PMALPHA) && p_light && !unshaded) { + + Light *light = p_light; + bool light_used = false; + VS::CanvasLightMode mode = VS::CANVAS_LIGHT_MODE_ADD; + state.uniforms.final_modulate = ci->final_modulate; // remove the canvas modulate + + while (light) { + + if (ci->light_mask & light->item_mask && p_z >= light->z_min && p_z <= light->z_max && ci->global_rect_cache.intersects_transformed(light->xform_cache, light->rect_cache)) { + + //intersects this light + + if (!light_used || mode != light->mode) { + + mode = light->mode; + + switch (mode) { + + case VS::CANVAS_LIGHT_MODE_ADD: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + + } break; + case VS::CANVAS_LIGHT_MODE_SUB: { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + } break; + case VS::CANVAS_LIGHT_MODE_MIX: + case VS::CANVAS_LIGHT_MODE_MASK: { + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + } break; + } + } + + if (!light_used) { + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING, true); + light_used = true; + } + + bool has_shadow = light->shadow_buffer.is_valid() && ci->light_mask & light->item_shadow_mask; + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS, has_shadow); + if (has_shadow) { + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_NEAREST, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_NONE); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF3, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF3); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF5, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF5); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF7, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF7); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF9, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF9); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF13, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF13); + } + + state.canvas_shader.bind(); + state.using_light = light; + state.using_shadow = has_shadow; + + //always re-set uniforms, since light parameters changed + _set_uniforms(); + state.canvas_shader.use_material((void *)material_ptr); + + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(light->texture); + if (!t) { + glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex); + } else { + t = t->get_ptr(); + + glBindTexture(t->target, t->tex_id); + } + + glActiveTexture(GL_TEXTURE0); + _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr); //redraw using light + + state.using_light = NULL; + } + + light = light->next_ptr; + } + + if (light_used) { + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_LIGHTING, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SHADOWS, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_NEAREST, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF3, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF5, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF7, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF9, false); + state.canvas_shader.set_conditional(CanvasShaderGLES2::SHADOW_FILTER_PCF13, false); + + state.canvas_shader.bind(); + + last_blend_mode = -1; + + /* + //this is set again, so it should not be needed anyway? + state.canvas_item_modulate = unshaded ? ci->final_modulate : Color( + ci->final_modulate.r * p_modulate.r, + ci->final_modulate.g * p_modulate.g, + ci->final_modulate.b * p_modulate.b, + ci->final_modulate.a * p_modulate.a ); + + + state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX,state.final_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX,Transform2D()); + state.canvas_shader.set_uniform(CanvasShaderGLES2::FINAL_MODULATE,state.canvas_item_modulate); + + glBlendEquation(GL_FUNC_ADD); + + if (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); + } + + //@TODO RESET canvas_blend_mode + */ + } + } + if (reclip) { glEnable(GL_SCISSOR_TEST); int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y); @@ -1003,14 +1723,129 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons if (current_clip) { glDisable(GL_SCISSOR_TEST); } + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_SKELETON, false); } void RasterizerCanvasGLES2::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) { } void RasterizerCanvasGLES2::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) { -} + RasterizerStorageGLES2::CanvasLightShadow *cls = storage->canvas_light_shadow_owner.get(p_buffer); + ERR_FAIL_COND(!cls); + + glDisable(GL_BLEND); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_DITHER); + glDisable(GL_CULL_FACE); + glDepthFunc(GL_LEQUAL); + glEnable(GL_DEPTH_TEST); + glDepthMask(true); + + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); + state.canvas_shadow_shader.bind(); + + glViewport(0, 0, cls->size, cls->height); + glClearDepth(1.0f); + glClearColor(1, 1, 1, 1); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + VS::CanvasOccluderPolygonCullMode cull = VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED; + + for (int i = 0; i < 4; i++) { + + //make sure it remains orthogonal, makes easy to read angle later + + Transform light; + light.origin[0] = p_light_xform[2][0]; + light.origin[1] = p_light_xform[2][1]; + light.basis[0][0] = p_light_xform[0][0]; + light.basis[0][1] = p_light_xform[1][0]; + light.basis[1][0] = p_light_xform[0][1]; + light.basis[1][1] = p_light_xform[1][1]; + + //light.basis.scale(Vector3(to_light.elements[0].length(),to_light.elements[1].length(),1)); + + //p_near=1; + CameraMatrix projection; + { + real_t fov = 90; + real_t nearp = p_near; + real_t farp = p_far; + real_t aspect = 1.0; + + real_t ymax = nearp * Math::tan(Math::deg2rad(fov * 0.5)); + real_t ymin = -ymax; + real_t xmin = ymin * aspect; + real_t xmax = ymax * aspect; + + projection.set_frustum(xmin, xmax, ymin, ymax, nearp, farp); + } + + Vector3 cam_target = Basis(Vector3(0, 0, Math_PI * 2 * (i / 4.0))).xform(Vector3(0, 1, 0)); + projection = projection * CameraMatrix(Transform().looking_at(cam_target, Vector3(0, 0, -1)).affine_inverse()); + + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::PROJECTION_MATRIX, projection); + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::LIGHT_MATRIX, light); + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::DISTANCE_NORM, 1.0 / p_far); + + if (i == 0) + *p_xform_cache = projection; + + glViewport(0, (cls->height / 4) * i, cls->size, cls->height / 4); + + LightOccluderInstance *instance = p_occluders; + + while (instance) { + + RasterizerStorageGLES2::CanvasOccluder *cc = storage->canvas_occluder_owner.get(instance->polygon_buffer); + if (!cc || cc->len == 0 || !(p_light_mask & instance->light_mask)) { + + instance = instance->next; + continue; + } + + state.canvas_shadow_shader.set_uniform(CanvasShadowShaderGLES2::WORLD_MATRIX, instance->xform_cache); + if (cull != instance->cull_cache) { + + cull = instance->cull_cache; + switch (cull) { + case VS::CANVAS_OCCLUDER_POLYGON_CULL_DISABLED: { + + glDisable(GL_CULL_FACE); + + } break; + case VS::CANVAS_OCCLUDER_POLYGON_CULL_CLOCKWISE: { + + glEnable(GL_CULL_FACE); + glCullFace(GL_FRONT); + } break; + case VS::CANVAS_OCCLUDER_POLYGON_CULL_COUNTER_CLOCKWISE: { + + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + + } break; + } + } + + glBindBuffer(GL_ARRAY_BUFFER, cc->vertex_id); + glEnableVertexAttribArray(VS::ARRAY_VERTEX); + glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, 0, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cc->index_id); + + glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0); + + instance = instance->next; + } + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); +} void RasterizerCanvasGLES2::reset_canvas() { glDisable(GL_CULL_FACE); @@ -1026,7 +1861,7 @@ void RasterizerCanvasGLES2::reset_canvas() { } // bind the back buffer to a texture so shaders can use it. - // It should probably use texture unit -3 (as GLES3 does as well) but currently that's buggy. + // It should probably use texture unit -3 (as GLES2 does as well) but currently that's buggy. // keeping this for now as there's nothing else that uses texture unit 2 // TODO ^ if (storage->frame.current_rt) { @@ -1051,7 +1886,104 @@ 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) { + + Vector2 window_size = OS::get_singleton()->get_window_size(); + int window_h = window_size.height; + int window_w = window_size.width; + + glBindFramebuffer(GL_FRAMEBUFFER, storage->system_fbo); + glViewport(0, 0, window_size.width, window_size.height); + canvas_begin(); + + if (black_image[MARGIN_LEFT].is_valid()) { + _bind_canvas_texture(black_image[MARGIN_LEFT], RID()); + Size2 sz(storage->texture_get_width(black_image[MARGIN_LEFT]), storage->texture_get_height(black_image[MARGIN_LEFT])); + draw_generic_textured_rect(Rect2(0, 0, black_margin[MARGIN_LEFT], window_h), Rect2(0, 0, sz.x, sz.y)); + } else if (black_margin[MARGIN_LEFT]) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + + draw_generic_textured_rect(Rect2(0, 0, black_margin[MARGIN_LEFT], window_h), Rect2(0, 0, 1, 1)); + } + + if (black_image[MARGIN_RIGHT].is_valid()) { + _bind_canvas_texture(black_image[MARGIN_RIGHT], RID()); + Size2 sz(storage->texture_get_width(black_image[MARGIN_RIGHT]), storage->texture_get_height(black_image[MARGIN_RIGHT])); + draw_generic_textured_rect(Rect2(window_w - black_margin[MARGIN_RIGHT], 0, black_margin[MARGIN_RIGHT], window_h), Rect2(0, 0, sz.x, sz.y)); + } else if (black_margin[MARGIN_RIGHT]) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + + draw_generic_textured_rect(Rect2(window_w - black_margin[MARGIN_RIGHT], 0, black_margin[MARGIN_RIGHT], window_h), Rect2(0, 0, 1, 1)); + } + + if (black_image[MARGIN_TOP].is_valid()) { + _bind_canvas_texture(black_image[MARGIN_TOP], RID()); + + Size2 sz(storage->texture_get_width(black_image[MARGIN_TOP]), storage->texture_get_height(black_image[MARGIN_TOP])); + draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[MARGIN_TOP]), Rect2(0, 0, sz.x, sz.y)); + + } else if (black_margin[MARGIN_TOP]) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + + draw_generic_textured_rect(Rect2(0, 0, window_w, black_margin[MARGIN_TOP]), Rect2(0, 0, 1, 1)); + } + + if (black_image[MARGIN_BOTTOM].is_valid()) { + + _bind_canvas_texture(black_image[MARGIN_BOTTOM], RID()); + + Size2 sz(storage->texture_get_width(black_image[MARGIN_BOTTOM]), storage->texture_get_height(black_image[MARGIN_BOTTOM])); + draw_generic_textured_rect(Rect2(0, window_h - black_margin[MARGIN_BOTTOM], window_w, black_margin[MARGIN_BOTTOM]), Rect2(0, 0, sz.x, sz.y)); + + } else if (black_margin[MARGIN_BOTTOM]) { + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex); + + draw_generic_textured_rect(Rect2(0, window_h - black_margin[MARGIN_BOTTOM], window_w, black_margin[MARGIN_BOTTOM]), Rect2(0, 0, 1, 1)); + } + + canvas_end(); } void RasterizerCanvasGLES2::initialize() { @@ -1076,6 +2008,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); @@ -1086,7 +2019,8 @@ void RasterizerCanvasGLES2::initialize() { glBindBuffer(GL_ARRAY_BUFFER, 0); - uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_size_kb", 128); + uint32_t index_size = GLOBAL_DEF("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); @@ -1150,7 +2084,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); @@ -1158,15 +2091,32 @@ void RasterizerCanvasGLES2::initialize() { glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); } + state.canvas_shadow_shader.init(); + state.canvas_shader.init(); state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); 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)); + + state.using_light = NULL; + state.using_transparent_rt = false; + state.using_skeleton = false; } void RasterizerCanvasGLES2::finalize() { } RasterizerCanvasGLES2::RasterizerCanvasGLES2() { +#ifdef GLES_OVER_GL + use_nvidia_rect_workaround = GLOBAL_GET("rendering/quality/2d/gles2_use_nvidia_rect_flicker_workaround"); +#else + // Not needed (a priori) on GLES devices + use_nvidia_rect_workaround = false; +#endif } diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index cda3ec79e7..ab636dca71 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -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 RASTERIZERCANVASGLES2_H #define RASTERIZERCANVASGLES2_H @@ -34,13 +35,18 @@ #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" +#include "shaders/canvas_shadow.glsl.gen.h" class RasterizerSceneGLES2; class RasterizerCanvasGLES2 : public RasterizerCanvas { public: + enum { + INSTANCE_ATTRIB_BASE = 8, + }; + struct Uniforms { Transform projection_matrix; @@ -69,16 +75,25 @@ public: Uniforms uniforms; bool canvas_texscreen_used; CanvasShaderGLES2 canvas_shader; - // CanvasShadowShaderGLES3 canvas_shadow_shader; + CanvasShadowShaderGLES2 canvas_shadow_shader; + LensDistortedShaderGLES2 lens_shader; bool using_texture_rect; bool using_ninepatch; + bool using_skeleton; + + Transform2D skeleton_transform; + Transform2D skeleton_transform_inverse; + Size2i skeleton_texture_size; RID current_tex; RID current_normal; RasterizerStorageGLES2::Texture *current_tex_ptr; Transform vp; + Light *using_light; + bool using_shadow; + bool using_transparent_rt; } state; @@ -88,6 +103,8 @@ public: RasterizerStorageGLES2 *storage; + bool use_nvidia_rect_workaround; + virtual RID light_internal_create(); virtual void light_internal_update(RID p_rid, Light *p_light); virtual void light_internal_free(RID p_rid); @@ -97,13 +114,12 @@ public: virtual void canvas_begin(); virtual void canvas_end(); - _FORCE_INLINE_ void _set_texture_rect_mode(bool p_enable, bool p_ninepatch = false); - _FORCE_INLINE_ void _draw_gui_primitive(int p_points, const Vector2 *p_vertices, const Color *p_colors, const Vector2 *p_uvs); - _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); + _FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor, const float *p_weights = NULL, const int *p_bones = NULL); _FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor); _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material); + void _copy_screen(const Rect2 &p_rect); _FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect); virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform); @@ -117,6 +133,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 bd03bd71f6..cbd0e4a5d5 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -32,7 +32,6 @@ #include "core/os/os.h" #include "core/project_settings.h" -#include "gl_context/context_gl.h" #define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 #define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 @@ -58,12 +57,34 @@ #define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 #define _EXT_DEBUG_OUTPUT 0x92E0 -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) +#ifndef GLAPIENTRY +#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED) #define GLAPIENTRY APIENTRY #else #define GLAPIENTRY #endif +#endif + +#ifndef IPHONE_ENABLED +// We include EGL below to get debug callback on GLES2 platforms, +// but EGL is not available on iOS. +#define CAN_DEBUG +#endif + +#if !defined(GLES_OVER_GL) && defined(CAN_DEBUG) +#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 + +#ifdef CAN_DEBUG 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 +94,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 +132,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL ERR_PRINTS(output); } +#endif // CAN_DEBUG typedef void (*DEBUGPROCARB)(GLenum source, GLenum type, @@ -179,7 +202,11 @@ Error RasterizerGLES2::is_viable() { return ERR_UNAVAILABLE; } } -#endif + + if (GLAD_GL_EXT_framebuffer_multisample) { + glRenderbufferStorageMultisample = glRenderbufferStorageMultisampleEXT; + } +#endif // GLES_OVER_GL #endif // GLAD_ENABLED @@ -191,7 +218,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); @@ -203,8 +230,9 @@ void RasterizerGLES2::initialize() { #endif // GLAD_ENABLED // For debugging +#ifdef CAN_DEBUG #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 +245,23 @@ void RasterizerGLES2::initialize() { GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello"); */ } -#endif +#else + 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 // GLES_OVER_GL +#endif // CAN_DEBUG const GLubyte *renderer = glGetString(GL_RENDERER); print_line("OpenGL ES 2.0 Renderer: " + String((const char *)renderer)); @@ -280,7 +324,7 @@ void RasterizerGLES2::set_current_render_target(RID p_render_target) { } } -void RasterizerGLES2::restore_render_target() { +void RasterizerGLES2::restore_render_target(bool p_3d_was_drawn) { ERR_FAIL_COND(storage->frame.current_rt == NULL); RasterizerStorageGLES2::RenderTarget *rt = storage->frame.current_rt; glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); @@ -294,7 +338,7 @@ void RasterizerGLES2::clear_render_target(const Color &p_color) { storage->frame.clear_request_color = p_color; } -void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) { +void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { if (p_image.is_null() || p_image->empty()) return; @@ -316,7 +360,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c canvas->canvas_begin(); RID texture = storage->texture_create(); - storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER); + storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0); storage->texture_set_data(texture, p_image); Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); @@ -361,7 +405,6 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re ERR_FAIL_COND(!rt); canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); - canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false); canvas->state.canvas_shader.set_custom_shader(0); canvas->state.canvas_shader.bind(); @@ -370,7 +413,11 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re glDisable(GL_BLEND); glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, rt->color); + if (rt->external.fbo != 0) { + glBindTexture(GL_TEXTURE_2D, rt->external.color); + } else { + glBindTexture(GL_TEXTURE_2D, rt->color); + } // TODO normals @@ -380,6 +427,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 c76d5f7f20..4d0d961ae4 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -51,14 +51,15 @@ public: virtual RasterizerCanvas *get_canvas(); virtual RasterizerScene *get_scene(); - virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale); + virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); virtual void initialize(); virtual void begin_frame(double frame_step); virtual void set_current_render_target(RID p_render_target); - virtual void restore_render_target(); + virtual void restore_render_target(bool p_3d_was_drawn); 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 true; } + RasterizerGLES2(); ~RasterizerGLES2(); }; diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 56605a9fe5..61bcfff419 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -36,12 +36,23 @@ #include "core/project_settings.h" #include "core/vmap.h" #include "rasterizer_canvas_gles2.h" +#include "servers/camera/camera_feed.h" #include "servers/visual/visual_server_raster.h" #ifndef GLES_OVER_GL #define glClearDepth glClearDepthf #endif +#ifndef GLES_OVER_GL +#ifdef IPHONE_ENABLED +#include <OpenGLES/ES2/glext.h> +//void *glResolveMultisampleFramebufferAPPLE; + +#define GL_READ_FRAMEBUFFER 0x8CA8 +#define GL_DRAW_FRAMEBUFFER 0x8CA9 +#endif +#endif + static const GLenum _cube_side_enum[6] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, @@ -60,6 +71,7 @@ RID RasterizerSceneGLES2::shadow_atlas_create() { ShadowAtlas *shadow_atlas = memnew(ShadowAtlas); shadow_atlas->fbo = 0; shadow_atlas->depth = 0; + shadow_atlas->color = 0; shadow_atlas->size = 0; shadow_atlas->smallest_subdiv = 0; @@ -82,11 +94,19 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) { // erase the old atlast if (shadow_atlas->fbo) { - glDeleteTextures(1, &shadow_atlas->depth); + if (storage->config.use_rgba_3d_shadows) { + glDeleteRenderbuffers(1, &shadow_atlas->depth); + } else { + glDeleteTextures(1, &shadow_atlas->depth); + } glDeleteFramebuffers(1, &shadow_atlas->fbo); + if (shadow_atlas->color) { + glDeleteTextures(1, &shadow_atlas->color); + } shadow_atlas->fbo = 0; shadow_atlas->depth = 0; + shadow_atlas->color = 0; } // erase shadow atlast references from lights @@ -106,17 +126,36 @@ void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) { // create a depth texture glActiveTexture(GL_TEXTURE0); - glGenTextures(1, &shadow_atlas->depth); - 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_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); + if (storage->config.use_rgba_3d_shadows) { + + //maximum compatibility, renderbuffer and RGBA shadow + glGenRenderbuffers(1, &shadow_atlas->depth); + glBindRenderbuffer(GL_RENDERBUFFER, directional_shadow.depth); + glRenderbufferStorage(GL_RENDERBUFFER, storage->config.depth_internalformat, shadow_atlas->size, shadow_atlas->size); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, shadow_atlas->depth); + + glGenTextures(1, &shadow_atlas->color); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, shadow_atlas->size, shadow_atlas->size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, shadow_atlas->color, 0); + } else { + //just depth texture + glGenTextures(1, &shadow_atlas->depth); + glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); + glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, shadow_atlas->size, shadow_atlas->size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, NULL); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_atlas->depth, 0); + 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); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_atlas->depth, 0); + } glViewport(0, 0, shadow_atlas->size, shadow_atlas->size); glDepthMask(GL_TRUE); @@ -141,7 +180,7 @@ void RasterizerSceneGLES2::shadow_atlas_set_quadrant_subdivision(RID p_atlas, in subdiv = int(Math::sqrt((float)subdiv)); - if (shadow_atlas->quadrants[p_quadrant].shadows.size() == subdiv) + if (shadow_atlas->quadrants[p_quadrant].shadows.size() == (int)subdiv) return; // erase all data from the quadrant @@ -437,29 +476,231 @@ 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->index = 0; + + for (int i = 0; i < 6; i++) { + glGenFramebuffers(1, &rpi->fbo[i]); + glGenTextures(1, &rpi->color[i]); + } + + 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); + + glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); + glRenderbufferStorage(GL_RENDERBUFFER, storage->config.depth_internalformat, size, size); + + 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); + + //Generate framebuffers for rendering + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); + glBindTexture(GL_TEXTURE_2D, rpi->color[i]); + glTexImage2D(GL_TEXTURE_2D, 0, internal_format, size, size, 0, format, type, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rpi->color[i], 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); + } + +#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 they won't be used later. + 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); + 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); + + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); + } + + 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); + ERR_FAIL_COND_V(rpi->current_resolution == 0, 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); + } + } + + 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 + + //first of all, copy rendered textures to cubemap + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); + glViewport(0, 0, size, size); + glCopyTexSubImage2D(_cube_side_enum[i], 0, 0, 0, 0, 0, size, size); + } + //do filtering + //vdc cache + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex); + + // now render to the framebuffer, mipmap level for mipmap level + int lod = 1; + + size >>= 1; + int mipmaps = 6; + + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); + storage->shaders.cubemap_filter.bind(); + + glBindFramebuffer(GL_FRAMEBUFFER, storage->resources.mipmap_blur_fbo); + + //blur + while (size >= 1) { + + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, storage->resources.mipmap_blur_color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, storage->resources.mipmap_blur_color, 0); + glViewport(0, 0, size, size); + glActiveTexture(GL_TEXTURE0); + + for (int i = 0; i < 6; i++) { + + 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); + glCopyTexSubImage2D(_cube_side_enum[i], lod, 0, 0, 0, 0, size, size); + } + + size >>= 1; + + lod++; + } + + // restore ranges + glActiveTexture(GL_TEXTURE0); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE3); //back to panorama + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); + + return true; } /* ENVIRONMENT API */ @@ -492,6 +733,13 @@ void RasterizerSceneGLES2::environment_set_sky_custom_fov(RID p_env, float p_sca env->sky_custom_fov = p_scale; } +void RasterizerSceneGLES2::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { + Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->sky_orientation = p_orientation; +} + void RasterizerSceneGLES2::environment_set_bg_color(RID p_env, const Color &p_color) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -522,19 +770,52 @@ void RasterizerSceneGLES2::environment_set_ambient_light(RID p_env, const Color env->ambient_sky_contribution = p_sky_contribution; } +void RasterizerSceneGLES2::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) { + Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->camera_feed_id = p_camera_feed_id; +} + void RasterizerSceneGLES2::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + + env->dof_blur_far_enabled = p_enable; + env->dof_blur_far_distance = p_distance; + env->dof_blur_far_transition = p_transition; + env->dof_blur_far_amount = p_amount; + env->dof_blur_far_quality = p_quality; } void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + + env->dof_blur_near_enabled = p_enable; + env->dof_blur_near_distance = p_distance; + env->dof_blur_near_transition = p_transition; + env->dof_blur_near_amount = p_amount; + env->dof_blur_near_quality = p_quality; } -void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) { +void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + + env->glow_enabled = p_enable; + env->glow_levels = p_level_flags; + env->glow_intensity = p_intensity; + env->glow_strength = p_strength; + env->glow_bloom = p_bloom_threshold; + env->glow_blend_mode = p_blend_mode; + env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold; + env->glow_hdr_bleed_scale = p_hdr_bleed_scale; + env->glow_hdr_luminance_cap = p_hdr_luminance_cap; + env->glow_bicubic_upscale = p_bicubic_upscale; } void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) { @@ -558,25 +839,51 @@ void RasterizerSceneGLES2::environment_set_tonemap(RID p_env, VS::EnvironmentTon } void RasterizerSceneGLES2::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + + env->adjustments_enabled = p_enable; + env->adjustments_brightness = p_brightness; + env->adjustments_contrast = p_contrast; + env->adjustments_saturation = p_saturation; + env->color_correction = p_ramp; } 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) { +void RasterizerSceneGLES2::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, 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_end = p_depth_end; + 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); } @@ -606,7 +913,10 @@ RID RasterizerSceneGLES2::light_instance_create(RID p_light) { light_instance->light_index = 0xFFFF; - ERR_FAIL_COND_V(!light_instance->light_ptr, RID()); + if (!light_instance->light_ptr) { + memdelete(light_instance); + ERR_FAIL_V_MSG(RID(), "Condition ' !light_instance->light_ptr ' is true."); + } light_instance->self = light_instance_owner.make_rid(light_instance); @@ -712,10 +1022,8 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G bool has_alpha = has_base_alpha || has_blend_alpha; bool mirror = p_instance->mirror; - bool no_cull = false; if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED) { - no_cull = true; mirror = false; } else if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_FRONT) { mirror = !mirror; @@ -738,7 +1046,6 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G //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); - no_cull = true; mirror = false; } else { p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); @@ -748,7 +1055,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G has_alpha = false; } - RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + RenderList::Element *e = (has_alpha || p_material->shader->spatial.no_depth_test) ? render_list.add_alpha_element() : render_list.add_element(); if (!e) { return; @@ -763,6 +1070,8 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G 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; + e->front_facing = false; if (e->geometry->last_pass != render_pass) { e->geometry->last_pass = render_pass; @@ -782,17 +1091,50 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G e->material_index = e->material->index; - e->refprobe_0_index = 0xFF; //refprobe disabled by default - e->refprobe_1_index = 0xFF; //refprobe disabled by default + if (mirror) { + e->front_facing = true; + } + + e->refprobe_0_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default + e->refprobe_1_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default if (!p_depth_pass) { e->depth_layer = e->instance->depth_layer; e->priority = p_material->render_priority; - //if (e->instance->reflection_probe_instances.size() > 0 ) { - // RasterizerStorageGLES2:: - //} + if (has_alpha && p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + //add element to opaque + RenderList::Element *eo = render_list.add_element(); + *eo = *e; + eo->use_accum_ptr = &eo->use_accum; + } + + 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; + }*/ + } //add directional lights @@ -827,8 +1169,8 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G LightInstance *li = light_instance_owner.getornull(e->instance->light_instances[i]); - if (li->light_index >= render_light_instance_count) { - continue; // too many + if (li->light_index >= render_light_instance_count || render_light_instances[li->light_index] != li) { + continue; // too many or light_index did not correspond to the light instances to be rendered } if (copy) { @@ -865,6 +1207,30 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G } } +void RasterizerSceneGLES2::_copy_texture_to_buffer(GLuint p_texture, GLuint p_buffer) { + + //copy to front buffer + glBindFramebuffer(GL_FRAMEBUFFER, p_buffer); + + 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, p_texture); + + glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + + storage->shaders.copy.bind(); + + storage->bind_quad_array(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindBuffer(GL_ARRAY_BUFFER, 0); +} + void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass) { render_pass++; @@ -887,10 +1253,10 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p int num_surfaces = mesh->surfaces.size(); - for (int i = 0; i < num_surfaces; i++) { - int material_index = instance->materials[i].is_valid() ? i : -1; + for (int j = 0; j < num_surfaces; j++) { + int material_index = instance->materials[j].is_valid() ? j : -1; - RasterizerStorageGLES2::Surface *surface = mesh->surfaces[i]; + RasterizerStorageGLES2::Surface *surface = mesh->surfaces[j]; _add_geometry(surface, instance, NULL, material_index, p_depth_pass, p_shadow_pass); } @@ -910,8 +1276,8 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p int ssize = mesh->surfaces.size(); - for (int i = 0; i < ssize; i++) { - RasterizerStorageGLES2::Surface *s = mesh->surfaces[i]; + for (int j = 0; j < ssize; j++) { + RasterizerStorageGLES2::Surface *s = mesh->surfaces[j]; _add_geometry(s, instance, multi_mesh, -1, p_depth_pass, p_shadow_pass); } } break; @@ -925,8 +1291,7 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p } break; default: { - - } break; + } } } } @@ -941,15 +1306,47 @@ static const GLenum gl_primitive[] = { GL_TRIANGLE_FAN }; -bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size) { +void RasterizerSceneGLES2::_set_cull(bool p_front, bool p_disabled, bool p_reverse_cull) { + + bool front = p_front; + if (p_reverse_cull) + front = !front; + + if (p_disabled != state.cull_disabled) { + if (p_disabled) + glDisable(GL_CULL_FACE); + else + glEnable(GL_CULL_FACE); + + state.cull_disabled = p_disabled; + } + + if (front != state.cull_front) { + + glCullFace(front ? GL_FRONT : GL_BACK); + state.cull_front = front; + } +} + +bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_alpha_pass, Size2i p_skeleton_tex_size) { // material parameters state.scene_shader.set_custom_shader(p_material->shader->custom_code_id); + if (p_material->shader->spatial.uses_screen_texture && storage->frame.current_rt) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color); + } + + if (p_material->shader->spatial.uses_depth_texture && storage->frame.current_rt) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); + } + bool shader_rebind = state.scene_shader.bind(); - if (p_material->shader->spatial.no_depth_test) { + if (p_material->shader->spatial.no_depth_test || p_material->shader->spatial.uses_depth_texture) { glDisable(GL_DEPTH_TEST); } else { glEnable(GL_DEPTH_TEST); @@ -959,41 +1356,25 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS: case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_OPAQUE: { - glDepthMask(!p_alpha_pass); + glDepthMask(!p_alpha_pass && !p_material->shader->spatial.uses_depth_texture); } break; case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALWAYS: { - glDepthMask(GL_TRUE); + glDepthMask(GL_TRUE && !p_material->shader->spatial.uses_depth_texture); } break; case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_NEVER: { glDepthMask(GL_FALSE); } break; } - // TODO whyyyyy???? - p_reverse_cull = true; - - switch (p_material->shader->spatial.cull_mode) { - case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED: { - glDisable(GL_CULL_FACE); - } break; - - case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_BACK: { - glEnable(GL_CULL_FACE); - glCullFace(p_reverse_cull ? GL_FRONT : GL_BACK); - } break; - case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_FRONT: { - glEnable(GL_CULL_FACE); - glCullFace(p_reverse_cull ? GL_BACK : GL_FRONT); - } break; - } - int tc = p_material->textures.size(); - Pair<StringName, RID> *textures = p_material->textures.ptrw(); + const Pair<StringName, RID> *textures = p_material->textures.ptr(); - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptrw(); + const ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptr(); state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size); + state.current_main_tex = 0; + for (int i = 0; i < tc; i++) { glActiveTexture(GL_TEXTURE0 + i); @@ -1021,9 +1402,30 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m continue; } + if (t->redraw_if_visible) { //must check before proxy because this is often used with proxies + VisualServerRaster::redraw_request(); + } + t = t->get_ptr(); +#ifdef TOOLS_ENABLED + if (t->detect_3d) { + t->detect_3d(t->detect_3d_ud); + } +#endif + +#ifdef TOOLS_ENABLED + if (t->detect_normal && texture_hints[i] == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL) { + t->detect_normal(t->detect_normal_ud); + } +#endif + if (t->render_target) + t->render_target->used_in_frame = true; + glBindTexture(t->target, t->tex_id); + if (i == 0) { + state.current_main_tex = t->tex_id; + } } state.scene_shader.use_material((void *)p_material); @@ -1046,27 +1448,28 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste 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); + glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset)); } else { glDisableVertexAttribArray(i); switch (i) { case VS::ARRAY_NORMAL: { - glVertexAttrib4f(VS::ARRAY_COLOR, 0.0, 0.0, 1, 1); + 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: {} + default: { + } } } } - bool clear_skeleton_buffer = !storage->config.float_texture_supported; + bool clear_skeleton_buffer = storage->config.use_skeleton_software; if (p_skeleton) { - if (storage->config.float_texture_supported) { + if (!storage->config.use_skeleton_software) { //use float texture workflow glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); glBindTexture(GL_TEXTURE_2D, p_skeleton->tex_id); @@ -1136,8 +1539,6 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste bone_weight[3] = (weight_ptr[3] / (float)0xFFFF); } - size_t offset = i * 12; - Transform transform; Transform bone_transforms[4] = { @@ -1176,33 +1577,28 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste //enable transform buffer and bind it glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - glEnableVertexAttribArray(VS::ARRAY_MAX + 0); - glEnableVertexAttribArray(VS::ARRAY_MAX + 1); - glEnableVertexAttribArray(VS::ARRAY_MAX + 2); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 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)); + 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)); clear_skeleton_buffer = false; } } if (clear_skeleton_buffer) { - // 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); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 2); } } 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); glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); @@ -1214,32 +1610,32 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste 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); + glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, CAST_INT_TO_UCHAR_PTR(s->attribs[i].offset)); } else { glDisableVertexAttribArray(i); switch (i) { case VS::ARRAY_NORMAL: { - glVertexAttrib4f(VS::ARRAY_COLOR, 0.0, 0.0, 1, 1); + 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: {} + default: { + } } } } - if (!storage->config.float_texture_supported) { - // just to make sure, clear skeleton buffer too - 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); - } + // 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); } break; @@ -1247,8 +1643,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste } break; default: { - - } break; + } } } @@ -1264,10 +1659,12 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { 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); + storage->info.render.vertices_count += s->index_array_len; } else { glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); + storage->info.render.vertices_count += 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); @@ -1280,7 +1677,7 @@ 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; case VS::INSTANCE_MULTIMESH: { @@ -1301,60 +1698,44 @@ 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(VS::ARRAY_MAX + 0, row[0]); - glVertexAttrib4fv(VS::ARRAY_MAX + 1, row[1]); - glVertexAttrib4fv(VS::ARRAY_MAX + 2, 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(VS::ARRAY_MAX + 3, 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(VS::ARRAY_MAX + 3, buffer + color_ofs); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); } + } else { + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, 1.0, 1.0, 1.0, 1.0); } if (multi_mesh->custom_data_floats) { if (multi_mesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); - glVertexAttrib4f(VS::ARRAY_MAX + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); + 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(VS::ARRAY_MAX + 4, buffer + custom_data_ofs); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 4, buffer + custom_data_ofs); } } 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); + storage->info.render.vertices_count += s->index_array_len; } else { glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); + storage->info.render.vertices_count += s->array_len; } } @@ -1387,11 +1768,10 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) { RasterizerStorageGLES2::Texture *t = storage->texture_owner.get(c.texture); - t = t->get_ptr(); - if (t->redraw_if_visible) { VisualServerRaster::redraw_request(); } + t = t->get_ptr(); #ifdef TOOLS_ENABLED if (t->detect_3d) { @@ -1415,7 +1795,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { if (!c.normals.empty()) { glEnableVertexAttribArray(VS::ARRAY_NORMAL); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.normals.ptr()); - glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Vector3) * vertices; } else { glDisableVertexAttribArray(VS::ARRAY_NORMAL); @@ -1424,7 +1804,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { if (!c.tangents.empty()) { glEnableVertexAttribArray(VS::ARRAY_TANGENT); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Plane) * vertices, c.tangents.ptr()); - glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, GL_FALSE, sizeof(Plane), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, GL_FALSE, sizeof(Plane), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Plane) * vertices; } else { glDisableVertexAttribArray(VS::ARRAY_TANGENT); @@ -1433,7 +1813,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { if (!c.colors.empty()) { glEnableVertexAttribArray(VS::ARRAY_COLOR); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Color) * vertices, c.colors.ptr()); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Color) * vertices; } else { glDisableVertexAttribArray(VS::ARRAY_COLOR); @@ -1442,7 +1822,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { if (!c.uvs.empty()) { glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs.ptr()); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Vector2) * vertices; } else { glDisableVertexAttribArray(VS::ARRAY_TEX_UV); @@ -1451,7 +1831,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { if (!c.uv2s.empty()) { glEnableVertexAttribArray(VS::ARRAY_TEX_UV2); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uv2s.ptr()); - glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Vector2) * vertices; } else { glDisableVertexAttribArray(VS::ARRAY_TEX_UV2); @@ -1459,7 +1839,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glEnableVertexAttribArray(VS::ARRAY_VERTEX); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.vertices.ptr()); - glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs)); glDrawArrays(gl_primitive[c.primitive], 0, c.vertices.size()); } @@ -1471,6 +1851,8 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { } } break; + default: { + } } } @@ -1514,10 +1896,14 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas } state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, p_light->light_ptr->directional_blend_splits); - if (p_light->light_ptr->shadow) { + 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); + if (storage->config.use_rgba_3d_shadows) { + glBindTexture(GL_TEXTURE_2D, directional_shadow.color); + } else { + 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); } @@ -1526,10 +1912,14 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas case VS::LIGHT_OMNI: { state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true); - if (shadow_atlas && p_light->light_ptr->shadow) { + 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); + if (storage->config.use_rgba_3d_shadows) { + glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); + } else { + 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); } @@ -1537,10 +1927,14 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas case VS::LIGHT_SPOT: { state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true); - if (shadow_atlas && p_light->light_ptr->shadow) { + 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); + if (storage->config.use_rgba_3d_shadows) { + glBindTexture(GL_TEXTURE_2D, shadow_atlas->color); + } else { + 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); } @@ -1548,19 +1942,22 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas } } -void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform) { +void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform, bool accum_pass) { RasterizerStorageGLES2::Light *light_ptr = light->light_ptr; //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; + float sign = (light_ptr->negative && !accum_pass) ? -1 : 1; //inverse color for base pass lights only 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); + Color shadow_color = light_ptr->shadow_color.to_linear(); + state.scene_shader.set_uniform(SceneShaderGLES2::SHADOW_COLOR, shadow_color); + //specific parameters switch (light_ptr->type) { @@ -1571,7 +1968,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado CameraMatrix matrices[4]; - if (light_ptr->shadow && directional_shadow.depth) { + if (!state.render_no_shadows && light_ptr->shadow && directional_shadow.depth) { int shadow_count = 0; Color split_offsets; @@ -1602,9 +1999,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado width /= 2; height /= 2; - if (k == 0) { - - } else if (k == 1) { + if (k == 1) { x += width; } else if (k == 2) { y += height; @@ -1617,9 +2012,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado height /= 2; - if (k == 0) { - - } else { + if (k != 0) { y += height; } } @@ -1662,11 +2055,10 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + float attenuation = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) { + if (!state.render_no_shadows && light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { uint32_t key = shadow_atlas->shadow_owners[light->self]; @@ -1716,8 +2108,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado 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 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]; @@ -1728,7 +2119,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - if (light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(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; @@ -1773,8 +2164,57 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado } } break; + default: { + } + } +} + +void RasterizerSceneGLES2::_setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env) { + + 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); + + 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; + } + + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_AMBIENT, ambient); + + Transform proj = (p_view_transform.inverse() * p_refprobe1->transform).affine_inverse(); + + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_LOCAL_MATRIX, proj); + } + + 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; + } + + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_AMBIENT, ambient); - default: break; + Transform proj = (p_view_transform.inverse() * p_refprobe2->transform).affine_inverse(); + + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_LOCAL_MATRIX, proj); } } @@ -1782,9 +2222,9 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_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; + Vector2 viewport_size = state.viewport_size; + + Vector2 screen_pixel_size = state.screen_pixel_size; bool use_radiance_map = false; if (!p_shadow && p_base_env) { @@ -1796,10 +2236,12 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, bool prev_unshaded = false; bool prev_instancing = false; + bool prev_depth_prepass = 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; Transform view_transform_inverse = p_view_transform.inverse(); CameraMatrix projection_inverse = p_projection.inverse(); @@ -1807,15 +2249,41 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, bool prev_base_pass = false; LightInstance *prev_light = NULL; bool prev_vertex_lit = false; + ReflectionProbeInstance *prev_refprobe_1 = NULL; + ReflectionProbeInstance *prev_refprobe_2 = NULL; int prev_blend_mode = -2; //will always catch the first go + state.cull_front = false; + state.cull_disabled = false; + glCullFace(GL_BACK); + glEnable(GL_CULL_FACE); + if (p_alpha_pass) { glEnable(GL_BLEND); } else { glDisable(GL_BLEND); } + 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); + if (p_env->fog_depth_end > 0) { + fog_max_distance = p_env->fog_depth_end; + } else { + fog_max_distance = p_projection.get_z_far(); + } + using_fog = true; + } + + RasterizerStorageGLES2::Texture *prev_lightmap = NULL; + float lightmap_energy = 1.0; + bool prev_use_lightmap_capture = false; + + storage->info.render.draw_call_count += p_element_count; + for (int i = 0; i < p_element_count; i++) { RenderList::Element *e = p_elements[i]; @@ -1825,8 +2293,15 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, 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) { + if (!p_shadow && material->shader) { bool unshaded = material->shader->spatial.unshaded; @@ -1860,12 +2335,18 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, _setup_light_type(light, shadow_atlas); rebind = true; + rebind_light = true; } int blend_mode = p_alpha_pass ? material->shader->spatial.blend_mode : -1; // -1 no blend, no mix if (accum_pass) { //accum pass force pass blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD; + if (rebind_light && light && light->light_ptr->negative) { + glBlendEquation(GL_FUNC_REVERSE_SUBTRACT); + glBlendFunc(GL_SRC_ALPHA, GL_ONE); + blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB; + } } if (prev_blend_mode != blend_mode) { @@ -1915,15 +2396,82 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, } //condition to enable vertex lighting on this object - bool vertex_lit = light && (material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading) && !unshaded; + 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 (vertex_lit != prev_vertex_lit) { state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit); prev_vertex_lit = vertex_lit; } + + 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 (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; + } + + use_lightmap_capture = !unshaded && !accum_pass && !e->instance->lightmap_capture_data.empty(); + + if (use_lightmap_capture != prev_use_lightmap_capture) { + + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, use_lightmap_capture); + rebind = true; + } + + if (!unshaded && !accum_pass && e->instance->lightmap.is_valid()) { + + 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; + } + } + } + + 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; + } } - bool instancing = e->instancing; + bool depth_prepass = false; + + if (!p_alpha_pass && material->shader->spatial.depth_draw_mode == RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + depth_prepass = true; + } + + if (depth_prepass != prev_depth_prepass) { + + state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, depth_prepass); + prev_depth_prepass = depth_prepass; + rebind = true; + } + + bool instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH; if (instancing != prev_instancing) { @@ -1936,8 +2484,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, if (skeleton != prev_skeleton) { if (skeleton) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, skeleton != NULL); - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, !storage->config.float_texture_supported); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, true); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, storage->config.use_skeleton_software); } else { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, false); @@ -1946,16 +2494,24 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, rebind = true; } - if (e->geometry != prev_geometry || skeleton != prev_skeleton) { + if (e->owner != prev_owner || e->geometry != prev_geometry || skeleton != prev_skeleton) { _setup_geometry(e, skeleton); + storage->info.render.surface_switch_count++; } 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)); + + storage->info.render.material_switch_count++; + shader_rebind = _setup_material(material, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); + if (shader_rebind) { + storage->info.render.shader_rebind_count++; + } } - if (i == 0 || shader_rebind) { //first time must rebindmakin + _set_cull(e->front_facing, material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED, p_reverse_cull); + + if (i == 0 || shader_rebind) { //first time must rebind if (p_shadow) { state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias); @@ -1966,60 +2522,126 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, } } else { if (use_radiance_map) { - state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform); + if (p_env) { + Transform sky_orientation(p_env->sky_orientation, Vector3(0.0, 0.0, 0.0)); + state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, sky_orientation.affine_inverse() * p_view_transform); + } else { + // would be a bit weird if we don't have this... + 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::BG_COLOR, p_env->bg_color); 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::BG_COLOR, state.default_bg); 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_COLOR, state.default_ambient); state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0); } - if (light) { - _setup_light(light, shadow_atlas, p_view_transform); + //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, view_transform_inverse); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); + 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::VIEWPORT_SIZE, viewport_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? + } + + if (rebind_light && light) { + _setup_light(light, shadow_atlas, p_view_transform, accum_pass); + } + + 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); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_DEPTH_PREPASS, 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) { +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, const Basis &p_sky_orientation) { ERR_FAIL_COND(!p_sky); RasterizerStorageGLES2::Texture *tex = storage->texture_owner.getornull(p_sky->panorama); @@ -2033,7 +2655,6 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C glDisable(GL_CULL_FACE); glDisable(GL_BLEND); glDepthFunc(GL_LEQUAL); - glColorMask(1, 1, 1, 1); // Camera CameraMatrix camera; @@ -2087,34 +2708,556 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C // bind sky vertex array.... glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, 0); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, ((uint8_t *)NULL) + sizeof(Vector3)); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, CAST_INT_TO_UCHAR_PTR(sizeof(Vector3))); 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); + // don't know why but I always have problems setting a uniform mat3, so we're using a transform + storage->shaders.copy.set_uniform(CopyShaderGLES2::SKY_TRANSFORM, Transform(p_sky_orientation, Vector3(0.0, 0.0, 0.0)).affine_inverse()); + + 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); glDisableVertexAttribArray(VS::ARRAY_VERTEX); 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::_post_process(Environment *env, const CameraMatrix &p_cam_projection) { + + //copy to front buffer + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1, 1, 1, 1); + + //no post process on small, transparent or render targets without an env + bool use_post_process = env && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; + use_post_process = use_post_process && storage->frame.current_rt->width >= 4 && storage->frame.current_rt->height >= 4; + use_post_process = use_post_process && storage->frame.current_rt->mip_maps_allocated; + + if (env) { + use_post_process = use_post_process && (env->adjustments_enabled || env->glow_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); + } + + GLuint next_buffer; + + if (use_post_process) { + next_buffer = storage->frame.current_rt->mip_maps[0].sizes[0].fbo; + } else { + // set next_buffer to front buffer so multisample blit can happen if needed + next_buffer = storage->frame.current_rt->fbo; + } + + // If using multisample buffer, resolve to post_process_effect buffer or to front buffer + if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) { +#ifdef GLES_OVER_GL + + glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, next_buffer); + glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +#elif IPHONE_ENABLED + + glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, next_buffer); + glResolveMultisampleFramebufferAPPLE(); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +#elif ANDROID_ENABLED + + // In GLES2 Android Blit is not available, so just copy color texture manually + _copy_texture_to_buffer(storage->frame.current_rt->multisample_color, next_buffer); +#endif + } else if (use_post_process) { + _copy_texture_to_buffer(storage->frame.current_rt->color, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); + } + + if (!use_post_process) { + return; + } + + // Order of operation + //1) DOF Blur (first blur, then copy to buffer applying the blur) //only on desktop + //2) Bloom (Glow) //only on desktop + //3) Adjustments + + // DOF Blur + + if (env->dof_blur_far_enabled) { + + int vp_h = storage->frame.current_rt->height; + int vp_w = storage->frame.current_rt->width; + + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, true); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_LOW); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH); + + state.effect_blur_shader.bind(); + int qsteps[3] = { 4, 10, 20 }; + + float radius = (env->dof_blur_far_amount * env->dof_blur_far_amount) / qsteps[env->dof_blur_far_quality]; + + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_far_distance); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_far_distance + env->dof_blur_far_transition); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(1, 0)); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_FAR, p_cam_projection.get_z_far()); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); + + glActiveTexture(GL_TEXTURE0); + + if (storage->frame.current_rt->mip_maps[0].color) { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); + } else { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first + + storage->_copy_screen(); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(0, 1)); + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); // copy to base level + storage->_copy_screen(); + + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_FAR_BLUR, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, false); + } + + if (env->dof_blur_near_enabled) { + + //convert texture to RGBA format if not already + if (!storage->frame.current_rt->used_dof_blur_near) { + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + + int vp_h = storage->frame.current_rt->height; + int vp_w = storage->frame.current_rt->width; + + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_BLUR, true); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, true); + + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_LOW); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, env->dof_blur_near_quality == VS::ENV_DOF_BLUR_QUALITY_HIGH); + + state.effect_blur_shader.bind(); + int qsteps[3] = { 4, 10, 20 }; + + float radius = (env->dof_blur_near_amount * env->dof_blur_near_amount) / qsteps[env->dof_blur_near_quality]; + + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_near_distance); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(1, 0)); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_FAR, p_cam_projection.get_z_far()); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); + + glActiveTexture(GL_TEXTURE0); + if (!storage->frame.current_rt->used_dof_blur_near) { + if (storage->frame.current_rt->mip_maps[0].color) { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); + } else { + for (int i = 0; i < storage->frame.current_rt->mip_maps[i].sizes.size(); i++) { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i].color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, storage->frame.current_rt->mip_maps[0].sizes[i].width, storage->frame.current_rt->mip_maps[0].sizes[i].height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); + } + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); //copy to front first + + storage->_copy_screen(); + + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, false); + state.effect_blur_shader.bind(); + + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_BEGIN, env->dof_blur_near_distance); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_END, env->dof_blur_near_distance - env->dof_blur_near_transition); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_DIR, Vector2(0, 1)); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::DOF_RADIUS, radius); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::CAMERA_Z_FAR, p_cam_projection.get_z_far()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color); + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[0].sizes[0].fbo); // copy to base level + + glEnable(GL_BLEND); + glBlendEquation(GL_FUNC_ADD); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + storage->_copy_screen(); + + glDisable(GL_BLEND); + + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_BLUR, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_NEAR_FIRST_TAP, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_LOW, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_MEDIUM, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::DOF_QUALITY_HIGH, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::USE_ORTHOGONAL_PROJECTION, false); + storage->frame.current_rt->used_dof_blur_near = true; + } + + if (env->dof_blur_near_enabled || env->dof_blur_far_enabled) { + //these needed to disable filtering, reenamble + glActiveTexture(GL_TEXTURE0); + if (storage->frame.current_rt->mip_maps[0].color) { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + } else { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + //glow + + int max_glow_level = -1; + int glow_mask = 0; + + if (env->glow_enabled) { + + for (int i = 0; i < VS::MAX_GLOW_LEVELS; i++) { + if (env->glow_levels & (1 << i)) { + + if (i >= storage->frame.current_rt->mip_maps[1].sizes.size()) { + max_glow_level = storage->frame.current_rt->mip_maps[1].sizes.size() - 1; + glow_mask |= 1 << max_glow_level; + + } else { + max_glow_level = i; + glow_mask |= (1 << i); + } + } + } + + for (int i = 0; i < (max_glow_level + 1); i++) { + + int vp_w = storage->frame.current_rt->mip_maps[1].sizes[i].width; + int vp_h = storage->frame.current_rt->mip_maps[1].sizes[i].height; + glViewport(0, 0, vp_w, vp_h); + //horizontal pass + if (i == 0) { + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_FIRST_PASS, true); + } + + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_GAUSSIAN_HORIZONTAL, true); + state.effect_blur_shader.bind(); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::LOD, storage->frame.current_rt->mip_maps[0].color ? float(i) : 0.0); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_STRENGTH, env->glow_strength); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::LUMINANCE_CAP, env->glow_hdr_luminance_cap); + + glActiveTexture(GL_TEXTURE0); + + if (storage->frame.current_rt->mip_maps[0].color) { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); + } else { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i].color); + } + + if (i == 0) { + + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_BLOOM, env->glow_bloom); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_HDR_THRESHOLD, env->glow_hdr_bleed_threshold); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_HDR_SCALE, env->glow_hdr_bleed_scale); + } + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[1].sizes[i].fbo); + storage->_copy_screen(); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_GAUSSIAN_HORIZONTAL, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_FIRST_PASS, false); + + //vertical pass + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_GAUSSIAN_VERTICAL, true); + state.effect_blur_shader.bind(); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::LOD, storage->frame.current_rt->mip_maps[0].color ? float(i) : 0.0); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES2::GLOW_STRENGTH, env->glow_strength); + glActiveTexture(GL_TEXTURE0); + + if (storage->frame.current_rt->mip_maps[0].color) { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[1].color); + } else { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[1].sizes[i].color); + } + + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->mip_maps[0].sizes[i + 1].fbo); //next level, since mipmaps[0] starts one level bigger + storage->_copy_screen(); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES2::GLOW_GAUSSIAN_VERTICAL, false); + } + + glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + } + + if (storage->frame.current_rt->external.fbo != 0) { + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); + } + + glActiveTexture(GL_TEXTURE0); + if (storage->frame.current_rt->mip_maps[0].color) { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); + } else { + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[0].color); + } + + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_FILTER_BICUBIC, env->glow_bicubic_upscale); + + if (max_glow_level >= 0) { + if (storage->frame.current_rt->mip_maps[0].color) { + for (int i = 0; i < (max_glow_level + 1); i++) { + + if (glow_mask & (1 << i)) { + if (i == 0) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, true); + } + if (i == 1) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, true); + } + if (i == 2) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, true); + } + if (i == 3) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, true); + } + if (i == 4) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, true); + } + if (i == 5) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, true); + } + if (i == 6) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, true); + } + } + } + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].color); + } else { + + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_MULTI_TEXTURE_GLOW, true); + int active_glow_level = 0; + for (int i = 0; i < (max_glow_level + 1); i++) { + + if (glow_mask & (1 << i)) { + active_glow_level++; + glActiveTexture(GL_TEXTURE0 + active_glow_level); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->mip_maps[0].sizes[i + 1].color); + if (active_glow_level == 1) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, true); + } + if (active_glow_level == 2) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, true); + } + if (active_glow_level == 3) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, true); + } + if (active_glow_level == 4) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, true); + } + if (active_glow_level == 5) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, true); + } + if (active_glow_level == 6) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, true); + } + if (active_glow_level == 7) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, true); + } + } + } + } + + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SCREEN); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, env->glow_blend_mode == VS::GLOW_BLEND_MODE_SOFTLIGHT); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, env->glow_blend_mode == VS::GLOW_BLEND_MODE_REPLACE); + } + + //Adjustments + if (env->adjustments_enabled) { + + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_BCS, true); + RasterizerStorageGLES2::Texture *tex = storage->texture_owner.getornull(env->color_correction); + if (tex) { + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_COLOR_CORRECTION, true); + glActiveTexture(GL_TEXTURE2); + glBindTexture(tex->target, tex->tex_id); + } + } + + state.tonemap_shader.bind(); + + if (max_glow_level >= 0) { + + state.tonemap_shader.set_uniform(TonemapShaderGLES2::GLOW_INTENSITY, env->glow_intensity); + int ss[2] = { + storage->frame.current_rt->width, + storage->frame.current_rt->height, + }; + glUniform2iv(state.tonemap_shader.get_uniform(TonemapShaderGLES2::GLOW_TEXTURE_SIZE), 1, ss); + } + + if (env->adjustments_enabled) { + + state.tonemap_shader.set_uniform(TonemapShaderGLES2::BCS, Vector3(env->adjustments_brightness, env->adjustments_contrast, env->adjustments_saturation)); + } + + storage->_copy_screen(); + + //turn off everything used + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL1, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL2, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL3, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL4, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL5, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL6, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_LEVEL7, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_REPLACE, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SCREEN, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_SOFTLIGHT, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_GLOW_FILTER_BICUBIC, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_MULTI_TEXTURE_GLOW, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_BCS, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES2::USE_COLOR_CORRECTION, 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) { + Transform cam_transform = p_cam_transform; + + storage->info.render.object_count += p_cull_count; + + GLuint current_fb = 0; + Environment *env = NULL; + + int viewport_width, viewport_height; + int viewport_x = 0; + int viewport_y = 0; + bool probe_interior = false; + bool reverse_cull = false; + + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]) { + cam_transform.basis.set_axis(1, -cam_transform.basis.get_axis(1)); + reverse_cull = true; + } + + 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]; + + viewport_width = probe->probe_ptr->resolution; + viewport_height = probe->probe_ptr->resolution; + + probe_interior = probe->probe_ptr->interior; + + } else { + state.render_no_shadows = false; + if (storage->frame.current_rt->external.fbo != 0) { + current_fb = storage->frame.current_rt->external.fbo; + } else { + if (storage->frame.current_rt->multisample_active) { + current_fb = storage->frame.current_rt->multisample_fbo; + } else { + current_fb = storage->frame.current_rt->fbo; + } + } + env = environment_owner.getornull(p_environment); + + viewport_width = storage->frame.current_rt->width; + viewport_height = storage->frame.current_rt->height; + viewport_x = storage->frame.current_rt->x; + + if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + viewport_y = OS::get_singleton()->get_window_size().height - viewport_height - storage->frame.current_rt->y; + } else { + viewport_y = storage->frame.current_rt->y; + } + } + + state.used_screen_texture = false; + state.viewport_size.x = viewport_width; + state.viewport_size.y = viewport_height; + state.screen_pixel_size.x = 1.0 / viewport_width; + state.screen_pixel_size.y = 1.0 / viewport_height; + //push back the directional lights if (p_light_cull_count) { - //harcoded limit of 256 lights + //hardcoded 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; @@ -2128,7 +3271,7 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) { render_directional_lights++; - //as goin in reverse, directional lights are always first anyway + //as going in reverse, directional lights are always first anyway } light->light_index = index; @@ -2143,10 +3286,22 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const render_light_instance_count = 0; } - glEnable(GL_BLEND); + 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 @@ -2156,15 +3311,54 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const // other stuff glBindFramebuffer(GL_FRAMEBUFFER, current_fb); + glViewport(viewport_x, viewport_y, viewport_width, viewport_height); + + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + + glScissor(viewport_x, viewport_y, viewport_width, viewport_height); + glEnable(GL_SCISSOR_TEST); + } glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); + // clear color + + Color clear_color(0, 0, 0, 1); + Ref<CameraFeed> feed; + + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + clear_color = Color(0, 0, 0, 0); + storage->frame.clear_request = false; + } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR || env->bg_mode == VS::ENV_BG_SKY) { + if (storage->frame.clear_request) { + clear_color = storage->frame.clear_request_color; + storage->frame.clear_request = false; + } + } else if (env->bg_mode == VS::ENV_BG_CANVAS || env->bg_mode == VS::ENV_BG_COLOR || env->bg_mode == VS::ENV_BG_COLOR_SKY) { + clear_color = env->bg_color; + storage->frame.clear_request = false; + } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) { + feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id); + storage->frame.clear_request = false; + } else { + storage->frame.clear_request = false; + } + + if (!env || env->bg_mode != VS::ENV_BG_KEEP) { + glClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a); + } + + state.default_ambient = Color(clear_color.r, clear_color.g, clear_color.b, 1.0); + state.default_bg = Color(clear_color.r, clear_color.g, clear_color.b, 1.0); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - storage->frame.clear_request = false; + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_DIRECT_TO_SCREEN]) { + glDisable(GL_SCISSOR_TEST); + } glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); @@ -2185,35 +3379,143 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const env_radiance_tex = sky->radiance; } } break; + case VS::ENV_BG_CAMERA_FEED: { + if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) { + // copy our camera feed to our background + + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, true); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_DISPLAY_TRANSFORM, true); + + if (feed->get_datatype() == CameraFeed::FEED_RGB) { + RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE); + VS::get_singleton()->texture_bind(camera_RGBA, 0); + + } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) { + RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE); + + VS::get_singleton()->texture_bind(camera_YCbCr, 0); + + storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, true); + + } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) { + RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE); + RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE); + + VS::get_singleton()->texture_bind(camera_Y, 0); + VS::get_singleton()->texture_bind(camera_CbCr, 1); + + storage->shaders.copy.set_conditional(CopyShaderGLES2::SEP_CBCR_TEXTURE, true); + storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, true); + }; + + storage->shaders.copy.bind(); + storage->shaders.copy.set_uniform(CopyShaderGLES2::DISPLAY_TRANSFORM, feed->get_transform()); + + storage->bind_quad_array(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glDisableVertexAttribArray(VS::ARRAY_VERTEX); + glDisableVertexAttribArray(VS::ARRAY_TEX_UV); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + // turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES2::SEP_CBCR_TEXTURE, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::YCBCR_TO_RGB, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_NO_ALPHA, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_DISPLAY_TRANSFORM, false); + + //restore + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + } else { + // don't have a feed, just show greenscreen :) + clear_color = Color(0.0, 1.0, 0.0, 1.0); + } + } break; default: { // FIXME: implement other background modes } break; } } + if (probe_interior) { + env_radiance_tex = 0; //do not use radiance texture on interiors + state.default_ambient = Color(0, 0, 0, 1); //black as default ambient for interior + state.default_bg = Color(0, 0, 0, 1); //black as default background for interior + } + + // render opaque things first + render_list.sort_by_key(false); + _render_render_list(render_list.elements, render_list.element_count, cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, reverse_cull, false, false); + + // then draw the sky after if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) { if (sky && sky->panorama.is_valid()) { - _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy); + _draw_sky(sky, p_cam_projection, cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation); } } - // render opaque things first - render_list.sort_by_key(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); + if (storage->frame.current_rt && state.used_screen_texture) { + //copy screen texture + + if (storage->frame.current_rt->multisample_active) { + // Resolve framebuffer to front buffer before copying +#ifdef GLES_OVER_GL + glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); + glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_NEAREST); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +#elif IPHONE_ENABLED + + glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->multisample_fbo); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); + glResolveMultisampleFramebufferAPPLE(); + + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); +#elif ANDROID_ENABLED + + // In GLES2 AndroidBlit is not available, so just copy color texture manually + _copy_texture_to_buffer(storage->frame.current_rt->multisample_color, storage->frame.current_rt->fbo); +#endif + } + + storage->canvas->_copy_screen(Rect2()); + + if (storage->frame.current_rt && storage->frame.current_rt->multisample_active) { + // Rebind the current framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, current_fb); + glViewport(0, 0, viewport_width, viewport_height); + } + } // alpha pass glBlendEquation(GL_FUNC_ADD); glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); - render_list.sort_by_depth(true); + render_list.sort_by_reverse_depth_and_priority(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); + _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, reverse_cull, true, false); - glDepthMask(GL_FALSE); - glDisable(GL_DEPTH_TEST); + if (p_reflection_probe.is_valid()) { + // Rendering to a probe so no need for post_processing + return; + } + + //post process + _post_process(env, p_cam_projection); //#define GLES2_SHADOW_ATLAS_DEBUG_VIEW @@ -2257,6 +3559,8 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const 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); @@ -2267,7 +3571,6 @@ 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; @@ -2325,9 +3628,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ width /= 2; height /= 2; - if (p_pass == 0) { - - } else if (p_pass == 1) { + if (p_pass == 1) { x += width; } else if (p_pass == 2) { y += height; @@ -2353,14 +3654,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]; @@ -2383,7 +3682,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ if (light->type == VS::LIGHT_OMNI) { // cubemap only - if (light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE) { + if (light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE && storage->config.support_shadow_cubemaps) { int cubemap_index = shadow_cubemaps.size() - 1; // find an appropriate cubemap to render to @@ -2452,7 +3751,9 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ glBindFramebuffer(GL_FRAMEBUFFER, fbo); glDepthMask(GL_TRUE); - glColorMask(0, 0, 0, 0); + if (!storage->config.use_rgba_3d_shadows) { + glColorMask(0, 0, 0, 0); + } if (custom_vp_size) { glViewport(0, 0, custom_vp_size, custom_vp_size); @@ -2479,7 +3780,7 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ 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) { + if (light->type == VS::LIGHT_OMNI && (light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE && storage->config.support_shadow_cubemaps) && p_pass == 5) { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo); @@ -2525,8 +3826,12 @@ 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); + if (storage->frame.current_rt) { + glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + } + if (!storage->config.use_rgba_3d_shadows) { + glColorMask(1, 1, 1, 1); + } } void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) { @@ -2534,6 +3839,54 @@ 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); + + for (int i = 0; i < 6; i++) { + glDeleteFramebuffers(1, &reflection_instance->fbo[i]); + glDeleteTextures(1, &reflection_instance->color[i]); + } + + if (reflection_instance->cubemap != 0) { + glDeleteTextures(1, &reflection_instance->cubemap); + } + glDeleteRenderbuffers(1, &reflection_instance->depth); + + reflection_probe_release_atlas_index(p_rid); + reflection_probe_instance_owner.free(p_rid); + memdelete(reflection_instance); + + } else { + return false; + } + return true; } @@ -2542,7 +3895,11 @@ void RasterizerSceneGLES2::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_dra void RasterizerSceneGLES2::initialize() { state.scene_shader.init(); + + state.scene_shader.set_conditional(SceneShaderGLES2::USE_RGBA_SHADOWS, storage->config.use_rgba_3d_shadows); state.cube_to_dp_shader.init(); + state.effect_blur_shader.init(); + state.tonemap_shader.init(); render_list.init(); @@ -2594,6 +3951,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); @@ -2602,7 +3960,7 @@ void RasterizerSceneGLES2::initialize() { } // cubemaps for shadows - { + if (storage->config.support_shadow_cubemaps) { //not going to be used int max_shadow_cubemap_sampler_size = 512; int cube_size = max_shadow_cubemap_sampler_size; @@ -2619,7 +3977,8 @@ 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, storage->config.depth_internalformat, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, NULL); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -2650,17 +4009,35 @@ void RasterizerSceneGLES2::initialize() { glGenFramebuffers(1, &directional_shadow.fbo); glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo); - glGenTextures(1, &directional_shadow.depth); - glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); + if (storage->config.use_rgba_3d_shadows) { + //maximum compatibility, renderbuffer and RGBA shadow + glGenRenderbuffers(1, &directional_shadow.depth); + glBindRenderbuffer(GL_RENDERBUFFER, directional_shadow.depth); + glRenderbufferStorage(GL_RENDERBUFFER, storage->config.depth_internalformat, directional_shadow.size, directional_shadow.size); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, directional_shadow.depth); + + glGenTextures(1, &directional_shadow.color); + glBindTexture(GL_TEXTURE_2D, directional_shadow.color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, directional_shadow.size, directional_shadow.size, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, directional_shadow.color, 0); + } else { + //just a depth buffer + glGenTextures(1, &directional_shadow.depth); + glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, storage->config.depth_internalformat, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, storage->config.depth_type, NULL); - 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); + 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); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0); + } GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -2670,9 +4047,7 @@ void RasterizerSceneGLES2::initialize() { shadow_filter_mode = SHADOW_FILTER_NEAREST; - RenderList::Element e; - e.sort_key = 0; - e.light_type1 = 1; + glFrontFace(GL_CW); } void RasterizerSceneGLES2::iteration() { diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 27cbc35299..7babcfeed1 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -35,10 +35,12 @@ #include "rasterizer_storage_gles2.h" #include "shaders/cube_to_dp.glsl.gen.h" +#include "shaders/effect_blur.glsl.gen.h" #include "shaders/scene.glsl.gen.h" +#include "shaders/tonemap.glsl.gen.h" /* -#include "drivers/gles3/shaders/effect_blur.glsl.gen.h" + #include "drivers/gles3/shaders/exposure.glsl.gen.h" #include "drivers/gles3/shaders/resolve.glsl.gen.h" #include "drivers/gles3/shaders/scene.glsl.gen.h" @@ -47,7 +49,6 @@ #include "drivers/gles3/shaders/ssao_blur.glsl.gen.h" #include "drivers/gles3/shaders/ssao_minify.glsl.gen.h" #include "drivers/gles3/shaders/subsurf_scattering.glsl.gen.h" -#include "drivers/gles3/shaders/tonemap.glsl.gen.h" */ @@ -59,6 +60,11 @@ public: SHADOW_FILTER_PCF13, }; + enum { + INSTANCE_ATTRIB_BASE = 8, + INSTANCE_BONE_BASE = 13, + }; + ShadowFilterMode shadow_filter_mode; RID default_material; @@ -94,10 +100,14 @@ public: SceneShaderGLES2 scene_shader; CubeToDpShaderGLES2 cube_to_dp_shader; + TonemapShaderGLES2 tonemap_shader; + EffectBlurShaderGLES2 effect_blur_shader; GLuint sky_verts; GLuint immediate_buffer; + Color default_ambient; + Color default_bg; // ResolveShaderGLES3 resolve_shader; // ScreenSpaceReflectionShaderGLES3 ssr_shader; @@ -107,7 +117,6 @@ public: // SsaoShaderGLES3 ssao_shader; // SsaoBlurShaderGLES3 ssao_blur_shader; // ExposureShaderGLES3 exposure_shader; - // TonemapShaderGLES3 tonemap_shader; /* struct SceneDataUBO { @@ -191,19 +200,25 @@ public: int directional_light_count; int reflection_probe_count; - bool cull_front; - bool cull_disabled; bool used_sss; bool using_contact_shadows; VS::ViewportDebugDraw debug_draw; */ + bool cull_front; + bool cull_disabled; + bool used_screen_texture; bool shadow_is_dual_parabolloid; float dual_parbolloid_direction; float dual_parbolloid_zfar; + bool render_no_shadows; + + Vector2 viewport_size; + + Vector2 screen_pixel_size; } state; /* SHADOW ATLAS API */ @@ -245,6 +260,7 @@ public: GLuint fbo; GLuint depth; + GLuint color; Map<RID, uint32_t> shadow_owners; }; @@ -268,6 +284,7 @@ public: struct DirectionalShadow { GLuint fbo; GLuint depth; + GLuint color; int light_count; int size; @@ -287,6 +304,37 @@ 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 color[6]; + GLuint depth; + GLuint cubemap; + + 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); @@ -302,25 +350,112 @@ public: RID sky; float sky_custom_fov; + Basis sky_orientation; Color bg_color; float bg_energy; float sky_ambient; + int camera_feed_id; + Color ambient_color; float ambient_energy; float ambient_sky_contribution; int canvas_max_layer; - Environment() { - bg_mode = VS::ENV_BG_CLEAR_COLOR; - sky_custom_fov = 0.0; - bg_energy = 1.0; - sky_ambient = 0; - ambient_energy = 1.0; - ambient_sky_contribution = 0.0; - canvas_max_layer = 0; + bool glow_enabled; + int glow_levels; + float glow_intensity; + float glow_strength; + float glow_bloom; + VS::EnvironmentGlowBlendMode glow_blend_mode; + float glow_hdr_bleed_threshold; + float glow_hdr_bleed_scale; + float glow_hdr_luminance_cap; + bool glow_bicubic_upscale; + + bool dof_blur_far_enabled; + float dof_blur_far_distance; + float dof_blur_far_transition; + float dof_blur_far_amount; + VS::EnvironmentDOFBlurQuality dof_blur_far_quality; + + bool dof_blur_near_enabled; + float dof_blur_near_distance; + float dof_blur_near_transition; + float dof_blur_near_amount; + VS::EnvironmentDOFBlurQuality dof_blur_near_quality; + + bool adjustments_enabled; + float adjustments_brightness; + float adjustments_contrast; + float adjustments_saturation; + RID color_correction; + + 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_end; + 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), + bg_energy(1.0), + sky_ambient(0), + camera_feed_id(0), + ambient_energy(1.0), + ambient_sky_contribution(0.0), + canvas_max_layer(0), + glow_enabled(false), + glow_levels((1 << 2) | (1 << 4)), + glow_intensity(0.8), + glow_strength(1.0), + glow_bloom(0.0), + glow_blend_mode(VS::GLOW_BLEND_MODE_SOFTLIGHT), + glow_hdr_bleed_threshold(1.0), + glow_hdr_bleed_scale(2.0), + glow_hdr_luminance_cap(12.0), + glow_bicubic_upscale(false), + dof_blur_far_enabled(false), + dof_blur_far_distance(10), + dof_blur_far_transition(5), + dof_blur_far_amount(0.1), + dof_blur_far_quality(VS::ENV_DOF_BLUR_QUALITY_MEDIUM), + dof_blur_near_enabled(false), + dof_blur_near_distance(2), + dof_blur_near_transition(1), + dof_blur_near_amount(0.1), + dof_blur_near_quality(VS::ENV_DOF_BLUR_QUALITY_MEDIUM), + adjustments_enabled(false), + adjustments_brightness(1.0), + adjustments_contrast(1.0), + adjustments_saturation(1.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_end(0), + fog_depth_curve(1), + fog_transmit_enabled(true), + fog_transmit_curve(1), + fog_height_enabled(false), + fog_height_min(10), + fog_height_max(0), + fog_height_curve(1) { } }; @@ -331,14 +466,16 @@ public: virtual void environment_set_background(RID p_env, VS::EnvironmentBG p_bg); virtual void environment_set_sky(RID p_env, RID p_sky); virtual void environment_set_sky_custom_fov(RID p_env, float p_scale); + virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation); virtual void environment_set_bg_color(RID p_env, const Color &p_color); virtual void environment_set_bg_energy(RID p_env, float p_energy); virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer); virtual void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0); + virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id); virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); - virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale); + virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness); @@ -349,7 +486,7 @@ public: virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp); virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount); - virtual void 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); + virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve); virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve); virtual bool is_environment(RID p_env); @@ -399,6 +536,7 @@ public: virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform); 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); + virtual bool light_instances_can_render_shadow_cube() const { return storage->config.support_shadow_cubemaps; } LightInstance **render_light_instances; int render_directional_lights; @@ -424,6 +562,7 @@ public: enum { MAX_LIGHTS = 255, + MAX_REFLECTION_PROBES = 255, DEFAULT_MAX_ELEMENTS = 65536 }; @@ -438,6 +577,7 @@ public: bool use_accum; //is this an add pass for multipass bool *use_accum_ptr; + bool front_facing; union { //TODO: should be endian swapped on big endian @@ -520,6 +660,27 @@ public: } } + struct SortByReverseDepthAndPriority { + + _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { + if (A->priority == B->priority) { + return A->instance->depth > B->instance->depth; + } else { + return A->priority < B->priority; + } + } + }; + + 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() { @@ -568,6 +729,7 @@ public: void _add_geometry(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass); void _add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass); + void _copy_texture_to_buffer(GLuint p_texture, GLuint p_buffer); 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 Transform &p_view_transform, @@ -581,14 +743,18 @@ public: bool p_alpha_pass, 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 _draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy, const Basis &p_sky_orientation); - _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 _set_cull(bool p_front, bool p_disabled, bool p_reverse_cull); + _FORCE_INLINE_ bool _setup_material(RasterizerStorageGLES2::Material *p_material, 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_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform, bool accum_pass); + _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); + void _post_process(Environment *env, const CameraMatrix &p_cam_projection); + 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); virtual bool free(RID p_rid); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index b3ce873b65..6faf76e395 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -44,8 +44,31 @@ GLuint RasterizerStorageGLES2::system_fbo = 0; #define _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2 #define _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3 +#define _EXT_COMPRESSED_RED_RGTC1_EXT 0x8DBB +#define _EXT_COMPRESSED_RED_RGTC1 0x8DBB +#define _EXT_COMPRESSED_SIGNED_RED_RGTC1 0x8DBC +#define _EXT_COMPRESSED_RG_RGTC2 0x8DBD +#define _EXT_COMPRESSED_SIGNED_RG_RGTC2 0x8DBE +#define _EXT_COMPRESSED_SIGNED_RED_RGTC1_EXT 0x8DBC +#define _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT 0x8DBD +#define _EXT_COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT 0x8DBE #define _EXT_ETC1_RGB8_OES 0x8D64 +#define _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG 0x8C00 +#define _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG 0x8C01 +#define _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG 0x8C02 +#define _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG 0x8C03 + +#define _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT 0x8A54 +#define _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT 0x8A55 +#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT 0x8A56 +#define _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT 0x8A57 + +#define _EXT_COMPRESSED_RGBA_BPTC_UNORM 0x8E8C +#define _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM 0x8E8D +#define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E +#define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F + #ifdef GLES_OVER_GL #define _GL_HALF_FLOAT_OES 0x140B #else @@ -54,16 +77,44 @@ GLuint RasterizerStorageGLES2::system_fbo = 0; #define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define _RED_OES 0x1903 + +#define _DEPTH_COMPONENT24_OES 0x81A6 + +#ifndef GLES_OVER_GL +#define glClearDepth glClearDepthf + +// enable extensions manually for android and ios +#include <dlfcn.h> // needed to load extensions + +#ifdef IPHONE_ENABLED + +#include <OpenGLES/ES2/glext.h> +//void *glRenderbufferStorageMultisampleAPPLE; +//void *glResolveMultisampleFramebufferAPPLE; +#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleAPPLE +#elif ANDROID_ENABLED + +#include <GLES2/gl2ext.h> +PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC glRenderbufferStorageMultisampleEXT; +PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC glFramebufferTexture2DMultisampleEXT; +#define glRenderbufferStorageMultisample glRenderbufferStorageMultisampleEXT +#define glFramebufferTexture2DMultisample glFramebufferTexture2DMultisampleEXT +#endif + +#define GL_MAX_SAMPLES 0x8D57 +#endif //!GLES_OVER_GL + 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); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, ((uint8_t *)NULL) + 8); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); glEnableVertexAttribArray(VS::ARRAY_VERTEX); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); } -Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const { +Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_will_need_resize) const { r_gl_format = 0; Ref<Image> image = p_image; @@ -93,9 +144,13 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_RG8: { - - ERR_EXPLAIN("RG texture not supported"); - ERR_FAIL_V(image); + ERR_PRINT("RG texture not supported, converting to RGB8."); + if (image.is_valid()) + image->convert(Image::FORMAT_RGB8); + r_real_format = Image::FORMAT_RGB8; + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; } break; case Image::FORMAT_RGB8: { @@ -128,42 +183,57 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_RF: { if (!config.float_texture_supported) { - ERR_EXPLAIN("R float texture not supported"); - ERR_FAIL_V(image); + ERR_PRINT("R float texture not supported, converting to RGB8."); + if (image.is_valid()) + image->convert(Image::FORMAT_RGB8); + r_real_format = Image::FORMAT_RGB8; + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + } else { + r_gl_internal_format = GL_ALPHA; + r_gl_format = GL_ALPHA; + r_gl_type = GL_FLOAT; } - - r_gl_internal_format = GL_ALPHA; - r_gl_format = GL_ALPHA; - r_gl_type = GL_FLOAT; } break; case Image::FORMAT_RGF: { - ERR_EXPLAIN("RG float texture not supported"); - ERR_FAIL_V(image); - + ERR_PRINT("RG float texture not supported, converting to RGB8."); + if (image.is_valid()) + image->convert(Image::FORMAT_RGB8); + r_real_format = Image::FORMAT_RGB8; + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; } break; case Image::FORMAT_RGBF: { if (!config.float_texture_supported) { - - ERR_EXPLAIN("RGB float texture not supported"); - ERR_FAIL_V(image); + ERR_PRINT("RGB float texture not supported, converting to RGB8."); + if (image.is_valid()) + image->convert(Image::FORMAT_RGB8); + r_real_format = Image::FORMAT_RGB8; + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + } else { + r_gl_internal_format = GL_RGB; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; } - - r_gl_internal_format = GL_RGB; - r_gl_format = GL_RGB; - r_gl_type = GL_FLOAT; - } break; case Image::FORMAT_RGBAF: { if (!config.float_texture_supported) { - - ERR_EXPLAIN("RGBA float texture not supported"); - ERR_FAIL_V(image); + ERR_PRINT("RGBA float texture not supported, converting to RGBA8."); + if (image.is_valid()) + image->convert(Image::FORMAT_RGBA8); + r_real_format = Image::FORMAT_RGBA8; + r_gl_internal_format = GL_RGBA; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + } else { + r_gl_internal_format = GL_RGBA; + r_gl_format = GL_RGBA; + r_gl_type = GL_FLOAT; } - - r_gl_internal_format = GL_RGBA; - r_gl_format = GL_RGBA; - r_gl_type = GL_FLOAT; - } break; case Image::FORMAT_RH: { need_decompress = true; @@ -191,11 +261,11 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_DXT1: { - r_compressed = true; - if (config.s3tc_supported) { + if (config.s3tc_supported && !p_will_need_resize) { r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; } else { need_decompress = true; } @@ -203,7 +273,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_DXT3: { - if (config.s3tc_supported) { + if (config.s3tc_supported && !p_will_need_resize) { r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; @@ -215,7 +285,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_DXT5: { - if (config.s3tc_supported) { + if (config.s3tc_supported && !p_will_need_resize) { r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; @@ -227,45 +297,134 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_RGTC_R: { - need_decompress = true; + if (config.rgtc_supported) { + + r_gl_internal_format = _EXT_COMPRESSED_RED_RGTC1_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + + need_decompress = true; + } } break; case Image::FORMAT_RGTC_RG: { - need_decompress = true; + if (config.rgtc_supported) { + + r_gl_internal_format = _EXT_COMPRESSED_RED_GREEN_RGTC2_EXT; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + } else { + + need_decompress = true; + } } break; case Image::FORMAT_BPTC_RGBA: { - need_decompress = true; + if (config.bptc_supported) { + + r_gl_internal_format = _EXT_COMPRESSED_RGBA_BPTC_UNORM; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + + need_decompress = true; + } } break; case Image::FORMAT_BPTC_RGBF: { - need_decompress = true; + if (config.bptc_supported) { + + r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + r_compressed = true; + } else { + + need_decompress = true; + } } break; case Image::FORMAT_BPTC_RGBFU: { + if (config.bptc_supported) { - need_decompress = true; + r_gl_internal_format = _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT; + r_gl_format = GL_RGB; + r_gl_type = GL_FLOAT; + r_compressed = true; + } else { + + need_decompress = true; + } } break; case Image::FORMAT_PVRTC2: { - need_decompress = true; + if (config.pvrtc_supported) { + + r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + + need_decompress = true; + } } break; case Image::FORMAT_PVRTC2A: { - need_decompress = true; + if (config.pvrtc_supported) { + + r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + + need_decompress = true; + } + } break; case Image::FORMAT_PVRTC4: { - need_decompress = true; + if (config.pvrtc_supported) { + + r_gl_internal_format = _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + + need_decompress = true; + } + } break; case Image::FORMAT_PVRTC4A: { - need_decompress = true; + if (config.pvrtc_supported) { + + r_gl_internal_format = _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + r_gl_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_compressed = true; + + } else { + + need_decompress = true; + } + } break; case Image::FORMAT_ETC: { - if (config.etc1_supported) { + if (config.etc1_supported && !p_will_need_resize) { r_gl_internal_format = _EXT_ETC1_RGB8_OES; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; @@ -311,17 +470,37 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_ if (need_decompress) { if (!image.is_null()) { + image = image->duplicate(); image->decompress(); ERR_FAIL_COND_V(image->is_compressed(), image); - image->convert(Image::FORMAT_RGBA8); + switch (image->get_format()) { + case Image::FORMAT_RGB8: { + r_gl_format = GL_RGB; + r_gl_internal_format = GL_RGB; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGB8; + r_compressed = false; + } break; + case Image::FORMAT_RGBA8: { + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGBA8; + r_compressed = false; + } break; + default: { + image->convert(Image::FORMAT_RGBA8); + r_gl_format = GL_RGBA; + r_gl_internal_format = GL_RGBA; + r_gl_type = GL_UNSIGNED_BYTE; + r_real_format = Image::FORMAT_RGBA8; + r_compressed = false; + + } break; + } } - r_gl_format = GL_RGBA; - r_gl_internal_format = GL_RGBA; - r_gl_type = GL_UNSIGNED_BYTE; - r_real_format = Image::FORMAT_RGBA8; - return image; } @@ -356,7 +535,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 @@ -392,11 +570,31 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ } } - Image::Format real_format; - _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed); - texture->alloc_width = texture->width; texture->alloc_height = texture->height; + texture->resize_to_po2 = false; + if (!config.support_npot_repeat_mipmap) { + int po2_width = next_power_of_2(p_width); + int po2_height = next_power_of_2(p_height); + + bool is_po2 = p_width == po2_width && p_height == po2_height; + + if (!is_po2 && (p_flags & VS::TEXTURE_FLAG_REPEAT || p_flags & VS::TEXTURE_FLAG_MIPMAPS)) { + + if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { + //not supported + ERR_PRINTS("Streaming texture for non power of 2 or has mipmaps on this hardware: " + texture->path + "'. Mipmaps and repeat disabled."); + texture->flags &= ~(VS::TEXTURE_FLAG_REPEAT | VS::TEXTURE_FLAG_MIPMAPS); + } else { + texture->alloc_height = po2_height; + texture->alloc_width = po2_width; + texture->resize_to_po2 = true; + } + } + } + + Image::Format real_format; + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); texture->gl_format_cache = format; texture->gl_type_cache = type; @@ -411,7 +609,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { //prealloc if video - glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, type, NULL); + glTexImage2D(texture->target, 0, internal_format, texture->alloc_width, texture->alloc_height, 0, format, type, NULL); } texture->active = true; @@ -436,7 +634,18 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p } Image::Format real_format; - Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed); + Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, texture->resize_to_po2); + + if (texture->resize_to_po2) { + if (p_image->is_compressed()) { + ERR_PRINTS("Texture '" + texture->path + "' was required to be a power of 2 (because it uses either mipmaps or repeat), so it was decompressed. This will hurt performance and memory usage."); + } + + if (img == p_image) { + img = img->duplicate(); + } + img->resize_to_po2(false); + } if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { @@ -497,22 +706,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(); @@ -588,11 +781,11 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) 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); + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, false); 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(); @@ -605,10 +798,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) for (int i = 0; i < texture->mipmaps; i++) { - int ofs = 0; - if (i > 0) { - ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1); - } + int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i); if (texture->compressed) { glPixelStorei(GL_PACK_ALIGNMENT, 4); @@ -619,17 +809,81 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) } } - wb = PoolVector<uint8_t>::Write(); + wb.release(); data.resize(data_size); - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, real_format, data)); + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, real_format, data)); 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, texture->resize_to_po2); + + 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.release(); + + 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 } @@ -716,6 +970,15 @@ uint32_t RasterizerStorageGLES2::texture_get_texid(RID p_texture) const { return texture->tex_id; } +void RasterizerStorageGLES2::texture_bind(RID p_texture, uint32_t p_texture_no) { + Texture *texture = texture_owner.getornull(p_texture); + + ERR_FAIL_COND(!texture); + + glActiveTexture(GL_TEXTURE0 + p_texture_no); + glBindTexture(texture->target, texture->tex_id); +} + uint32_t RasterizerStorageGLES2::texture_get_width(RID p_texture) const { Texture *texture = texture_owner.getornull(p_texture); @@ -795,6 +1058,17 @@ void RasterizerStorageGLES2::textures_keep_original(bool p_enable) { config.keep_original_textures = p_enable; } +Size2 RasterizerStorageGLES2::texture_size_with_proxy(RID p_texture) const { + + const Texture *texture = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!texture, Size2()); + if (texture->proxy) { + return Size2(texture->proxy->width, texture->proxy->height); + } else { + return Size2(texture->width, texture->height); + } +} + void RasterizerStorageGLES2::texture_set_proxy(RID p_texture, RID p_proxy) { Texture *texture = texture_owner.getornull(p_texture); ERR_FAIL_COND(!texture); @@ -912,30 +1186,27 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra glGenTextures(1, &sky->radiance); glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); - // Now we create a new framebuffer. The new cubemap images will be used as - // 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 / 2; //divide by two because its a cubemap (this is an approximation because GLES3 uses a dual paraboloid) - int size = p_radiance_size; + GLenum internal_format = GL_RGB; + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; - 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; + // 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); + } - GLenum internal_format = GL_RGBA; - GLenum format = GL_RGBA; - GLenum type = GL_UNSIGNED_BYTE; // This is suboptimal... TODO other format for FBO? + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + //no filters for now + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_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); - // Set the initial (empty) mipmaps +#else while (size >= 1) { for (int i = 0; i < 6; i++) { @@ -946,28 +1217,54 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra size >>= 1; } +#endif + //framebuffer - lod = 0; - mm_level = mipmaps; + glBindFramebuffer(GL_FRAMEBUFFER, resources.mipmap_blur_fbo); - size = p_radiance_size; + int mipmaps = 6; + int lod = 0; + int mm_level = mipmaps; + size = p_radiance_size / 2; + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, true); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, true); + shaders.cubemap_filter.bind(); - // now render to the framebuffer, mipmap level for mipmap level + // third, render to the framebuffer using separate textures, then copy to mipmaps while (size >= 1) { - for (int i = 0; i < 6; i++) { - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], sky->radiance, lod); + //make framebuffer size the texture size, need to use a separate texture for compatibility + glActiveTexture(GL_TEXTURE3); + glBindTexture(GL_TEXTURE_2D, resources.mipmap_blur_color); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, size, size, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, resources.mipmap_blur_color, 0); - glViewport(0, 0, size, size); + if (lod == 1) { + //bind panorama for smaller lods - bind_quad_array(); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false); + shaders.cubemap_filter.bind(); + } + glViewport(0, 0, size, size); + bind_quad_array(); + + glActiveTexture(GL_TEXTURE2); //back to panorama + + for (int i = 0; i < 6; i++) { shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); - float roughness = mm_level ? lod / (float)(mipmaps - 1) : 1; + float roughness = mm_level >= 0 ? lod / (float)(mipmaps - 1) : 1; + roughness = MIN(1.0, roughness); //keep max at 1 shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness); + shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glCopyTexSubImage2D(_cube_side_enum[i], lod, 0, 0, 0, 0, size, size); } size >>= 1; @@ -977,16 +1274,28 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra lod++; } + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_DIRECT_WRITE, false); + // restore ranges + glActiveTexture(GL_TEXTURE2); //back to panorama 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); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE3); //back to panorama + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, 0); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, 0); + // Framebuffer did its job. thank mr framebuffer + glActiveTexture(GL_TEXTURE0); //back to panorama glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); - glDeleteFramebuffers(1, &tmp_fb); } /* SHADER API */ @@ -1067,15 +1376,18 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { p_shader->uniforms.clear(); + if (p_shader->code == String()) { + return; //just invalid, but no error + } + ShaderCompilerGLES2::GeneratedCode gen_code; ShaderCompilerGLES2::IdentifierActions *actions = NULL; switch (p_shader->mode) { - // TODO - case VS::SHADER_CANVAS_ITEM: { + p_shader->canvas_item.light_mode = Shader::CanvasItem::LIGHT_MODE_NORMAL; p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX; p_shader->canvas_item.uses_screen_texture = false; @@ -1088,8 +1400,8 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { shaders.actions_canvas.render_mode_values["blend_mul"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MUL); shaders.actions_canvas.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_PMALPHA); - // shaders.actions_canvas.render_mode_values["unshaded"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED); - // shaders.actions_canvas.render_mode_values["light_only"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY); + shaders.actions_canvas.render_mode_values["unshaded"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_UNSHADED); + shaders.actions_canvas.render_mode_values["light_only"] = Pair<int *, int>(&p_shader->canvas_item.light_mode, Shader::CanvasItem::LIGHT_MODE_LIGHT_ONLY); shaders.actions_canvas.usage_flag_pointers["SCREEN_UV"] = &p_shader->canvas_item.uses_screen_uv; shaders.actions_canvas.usage_flag_pointers["SCREEN_PIXEL_SIZE"] = &p_shader->canvas_item.uses_screen_uv; @@ -1154,6 +1466,14 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { actions = &shaders.actions_scene; actions->uniforms = &p_shader->uniforms; + + if (p_shader->spatial.uses_screen_texture && p_shader->spatial.uses_depth_texture) { + ERR_PRINT_ONCE("Using both SCREEN_TEXTURE and DEPTH_TEXTURE is not supported in GLES2"); + } + + if (p_shader->spatial.uses_depth_texture && !config.support_depth_texture) { + ERR_PRINT_ONCE("Using DEPTH_TEXTURE is not permitted on this hardware, operation will fail."); + } } break; default: { @@ -1162,8 +1482,9 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { } Error err = shaders.compiler.compile(p_shader->mode, p_shader->code, actions, p_shader->path, gen_code); - - ERR_FAIL_COND(err != OK); + if (err != OK) { + return; + } p_shader->shader->set_custom_shader_code(p_shader->custom_code_id, gen_code.vertex, gen_code.vertex_global, gen_code.fragment, gen_code.light, gen_code.fragment_global, gen_code.uniforms, gen_code.texture_uniforms, gen_code.custom_defines); @@ -1252,7 +1573,7 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]); + pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); } } break; @@ -1267,6 +1588,10 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn case ShaderLanguage::TYPE_FLOAT: { pi.type = Variant::REAL; + if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { + pi.hint = PROPERTY_HINT_RANGE; + pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); + } } break; case ShaderLanguage::TYPE_VEC2: { @@ -1310,8 +1635,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; } @@ -1430,8 +1760,9 @@ Variant RasterizerStorageGLES2::material_get_param_default(RID p_material, const 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); + ShaderLanguage::ShaderNode::Uniform uniform = material->shader->uniforms[p_param]; + Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); } } return Variant(); @@ -1539,7 +1870,7 @@ void RasterizerStorageGLES2::_update_material(Material *p_material) { if (p_material->shader && p_material->shader->mode == VS::SHADER_SPATIAL) { if (p_material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX && - (!p_material->shader->spatial.uses_alpha || (p_material->shader->spatial.uses_alpha && p_material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))) { + (!p_material->shader->spatial.uses_alpha || p_material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) { can_cast_shadow = true; } @@ -1560,7 +1891,7 @@ void RasterizerStorageGLES2::_update_material(Material *p_material) { } for (Map<RasterizerScene::InstanceBase *, int>::Element *E = p_material->instance_owners.front(); E; E = E->next()) { - E->key()->base_material_changed(); + E->key()->base_changed(false, true); } } } @@ -1644,8 +1975,196 @@ RID RasterizerStorageGLES2::mesh_create() { return mesh_owner.make_rid(mesh); } +static PoolVector<uint8_t> _unpack_half_floats(const PoolVector<uint8_t> &array, uint32_t &format, int p_vertices) { + + uint32_t p_format = format; + + static int src_size[VS::ARRAY_MAX]; + static int dst_size[VS::ARRAY_MAX]; + static int to_convert[VS::ARRAY_MAX]; + + int src_stride = 0; + int dst_stride = 0; + + for (int i = 0; i < VS::ARRAY_MAX; i++) { + + to_convert[i] = 0; + if (!(p_format & (1 << i))) { + src_size[i] = 0; + dst_size[i] = 0; + continue; + } + + switch (i) { + + case VS::ARRAY_VERTEX: { + + if (p_format & VS::ARRAY_COMPRESS_VERTEX) { + + if (p_format & VS::ARRAY_FLAG_USE_2D_VERTICES) { + src_size[i] = 4; + dst_size[i] = 8; + to_convert[i] = 2; + } else { + src_size[i] = 8; + dst_size[i] = 12; + to_convert[i] = 3; + } + + format &= ~VS::ARRAY_COMPRESS_VERTEX; + } else { + + if (p_format & VS::ARRAY_FLAG_USE_2D_VERTICES) { + src_size[i] = 8; + dst_size[i] = 8; + } else { + src_size[i] = 12; + dst_size[i] = 12; + } + } + + } break; + case VS::ARRAY_NORMAL: { + + if (p_format & VS::ARRAY_COMPRESS_NORMAL) { + src_size[i] = 4; + dst_size[i] = 4; + } else { + src_size[i] = 12; + dst_size[i] = 12; + } + + } break; + case VS::ARRAY_TANGENT: { + + if (p_format & VS::ARRAY_COMPRESS_TANGENT) { + src_size[i] = 4; + dst_size[i] = 4; + } else { + src_size[i] = 16; + dst_size[i] = 16; + } + + } break; + case VS::ARRAY_COLOR: { + + if (p_format & VS::ARRAY_COMPRESS_COLOR) { + src_size[i] = 4; + dst_size[i] = 4; + } else { + src_size[i] = 16; + dst_size[i] = 16; + } + + } break; + case VS::ARRAY_TEX_UV: { + + if (p_format & VS::ARRAY_COMPRESS_TEX_UV) { + src_size[i] = 4; + to_convert[i] = 2; + format &= ~VS::ARRAY_COMPRESS_TEX_UV; + } else { + src_size[i] = 8; + } + + dst_size[i] = 8; + + } break; + case VS::ARRAY_TEX_UV2: { + + if (p_format & VS::ARRAY_COMPRESS_TEX_UV2) { + src_size[i] = 4; + to_convert[i] = 2; + format &= ~VS::ARRAY_COMPRESS_TEX_UV2; + } else { + src_size[i] = 8; + } + + dst_size[i] = 8; + + } break; + case VS::ARRAY_BONES: { + + if (p_format & VS::ARRAY_FLAG_USE_16_BIT_BONES) { + src_size[i] = 8; + dst_size[i] = 8; + } else { + src_size[i] = 4; + dst_size[i] = 4; + } + + } break; + case VS::ARRAY_WEIGHTS: { + + if (p_format & VS::ARRAY_COMPRESS_WEIGHTS) { + src_size[i] = 8; + dst_size[i] = 8; + } else { + src_size[i] = 16; + dst_size[i] = 16; + } + + } break; + case VS::ARRAY_INDEX: { + + src_size[i] = 0; + dst_size[i] = 0; + + } break; + } + + src_stride += src_size[i]; + dst_stride += dst_size[i]; + } + + PoolVector<uint8_t> ret; + ret.resize(p_vertices * dst_stride); + + PoolVector<uint8_t>::Read r = array.read(); + PoolVector<uint8_t>::Write w = ret.write(); + + int src_offset = 0; + int dst_offset = 0; + + for (int i = 0; i < VS::ARRAY_MAX; i++) { + + if (src_size[i] == 0) { + continue; //no go + } + const uint8_t *rptr = r.ptr(); + uint8_t *wptr = w.ptr(); + if (to_convert[i]) { //converting + + for (int j = 0; j < p_vertices; j++) { + const uint16_t *src = (const uint16_t *)&rptr[src_stride * j + src_offset]; + float *dst = (float *)&wptr[dst_stride * j + dst_offset]; + + for (int k = 0; k < to_convert[i]; k++) { + + dst[k] = Math::half_to_float(src[k]); + } + } + + } else { + //just copy + for (int j = 0; j < p_vertices; j++) { + for (int k = 0; k < src_size[i]; k++) { + wptr[dst_stride * j + dst_offset + k] = rptr[src_stride * j + src_offset + k]; + } + } + } + + src_offset += src_size[i]; + dst_offset += dst_size[i]; + } + + r.release(); + w.release(); + + return ret; +} + void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS::PrimitiveType p_primitive, const PoolVector<uint8_t> &p_array, int p_vertex_count, const PoolVector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<PoolVector<uint8_t> > &p_blend_shapes, const Vector<AABB> &p_bone_aabbs) { - PoolVector<uint8_t> array = p_array; Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND(!mesh); @@ -1655,8 +2174,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: //must have index and bones, both. { uint32_t bones_weight = VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS; - ERR_EXPLAIN("Array must have both bones and weights in format or none."); - ERR_FAIL_COND((p_format & bones_weight) && (p_format & bones_weight) != bones_weight); + ERR_FAIL_COND_MSG((p_format & bones_weight) && (p_format & bones_weight) != bones_weight, "Array must have both bones and weights in format or none."); } //bool has_morph = p_blend_shapes.size(); @@ -1664,6 +2182,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: Surface::Attrib attribs[VS::ARRAY_MAX]; int stride = 0; + bool uses_half_float = false; for (int i = 0; i < VS::ARRAY_MAX; i++) { @@ -1692,6 +2211,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: if (p_format & VS::ARRAY_COMPRESS_VERTEX) { attribs[i].type = _GL_HALF_FLOAT_OES; stride += attribs[i].size * 2; + uses_half_float = true; } else { attribs[i].type = GL_FLOAT; stride += attribs[i].size * 4; @@ -1752,6 +2272,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: if (p_format & VS::ARRAY_COMPRESS_TEX_UV) { attribs[i].type = _GL_HALF_FLOAT_OES; stride += 4; + uses_half_float = true; } else { attribs[i].type = GL_FLOAT; stride += 8; @@ -1767,6 +2288,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: if (p_format & VS::ARRAY_COMPRESS_TEX_UV2) { attribs[i].type = _GL_HALF_FLOAT_OES; stride += 4; + uses_half_float = true; } else { attribs[i].type = GL_FLOAT; stride += 8; @@ -1829,6 +2351,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: } //validate sizes + PoolVector<uint8_t> array = p_array; int array_size = stride * p_vertex_count; int index_array_size = 0; @@ -1860,6 +2383,15 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: ERR_FAIL_COND(array.size() != array_size); + if (!config.support_half_float_vertices && uses_half_float) { + + uint32_t new_format = p_format; + PoolVector<uint8_t> unpacked_array = _unpack_half_floats(array, new_format, p_vertex_count); + + mesh_add_surface(p_mesh, new_format, p_primitive, unpacked_array, p_vertex_count, p_index_array, p_index_count, p_aabb, p_blend_shapes, p_bone_aabbs); + return; //do not go any further, above function used unpacked stuff will be used instead. + } + if (p_format & VS::ARRAY_FORMAT_INDEX) { index_array_size = attribs[VS::ARRAY_INDEX].stride * p_index_count; @@ -1890,14 +2422,31 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: surface->aabb = p_aabb; surface->max_bone = p_bone_aabbs.size(); - +#ifdef TOOLS_ENABLED + surface->blend_shape_data = p_blend_shapes; + if (surface->blend_shape_data.size()) { + ERR_PRINT_ONCE("Blend shapes are not supported in OpenGL ES 2.0"); + } surface->data = array; surface->index_data = p_index_array; +#else + // Even on non-tools builds, a copy of the surface->data is needed in certain circumstances. + // Rigged meshes using the USE_SKELETON_SOFTWARE path need to read bone data + // from surface->data. + + // if USE_SKELETON_SOFTWARE is active + if (config.use_skeleton_software) { + // if this geometry is used specifically for skinning + if (p_format & (VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS)) + surface->data = array; + } + // An alternative is to always make a copy of surface->data. +#endif surface->total_data_size += surface->array_byte_size + surface->index_array_byte_size; for (int i = 0; i < surface->skeleton_bone_used.size(); i++) { - surface->skeleton_bone_used.write[i] = surface->skeleton_bone_aabb[i].size.x < 0 || surface->skeleton_bone_aabb[i].size.y < 0 || surface->skeleton_bone_aabb[i].size.z < 0; + surface->skeleton_bone_used.write[i] = !(surface->skeleton_bone_aabb[i].size.x < 0 || surface->skeleton_bone_aabb[i].size.y < 0 || surface->skeleton_bone_aabb[i].size.z < 0); } for (int i = 0; i < VS::ARRAY_MAX; i++) { @@ -1921,6 +2470,8 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_array_size, ir.ptr(), GL_STATIC_DRAW); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } else { + surface->index_id = 0; } // TODO generate wireframes @@ -1947,7 +2498,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: } mesh->surfaces.push_back(surface); - mesh->instance_change_notify(); + mesh->instance_change_notify(true, true); info.vertex_mem += surface->total_data_size; } @@ -1960,12 +2511,12 @@ void RasterizerStorageGLES2::mesh_set_blend_shape_count(RID p_mesh, int p_amount ERR_FAIL_COND(p_amount < 0); mesh->blend_shape_count = p_amount; + mesh->instance_change_notify(true, false); } int RasterizerStorageGLES2::mesh_get_blend_shape_count(RID p_mesh) const { const Mesh *mesh = mesh_owner.getornull(p_mesh); ERR_FAIL_COND_V(!mesh, 0); - return mesh->blend_shape_count; } @@ -2017,7 +2568,7 @@ void RasterizerStorageGLES2::mesh_surface_set_material(RID p_mesh, int p_surface _material_add_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]); } - mesh->instance_material_change_notify(); + mesh->instance_change_notify(false, true); } RID RasterizerStorageGLES2::mesh_surface_get_material(RID p_mesh, int p_surface) const { @@ -2051,7 +2602,9 @@ PoolVector<uint8_t> RasterizerStorageGLES2::mesh_surface_get_array(RID p_mesh, i ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), PoolVector<uint8_t>()); Surface *surface = mesh->surfaces[p_surface]; - +#ifndef TOOLS_ENABLED + ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data"); +#endif return surface->data; } @@ -2091,8 +2644,14 @@ AABB RasterizerStorageGLES2::mesh_surface_get_aabb(RID p_mesh, int p_surface) co } Vector<PoolVector<uint8_t> > RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const { - WARN_PRINT("GLES2 mesh_surface_get_blend_shapes is not implemented"); - return Vector<PoolVector<uint8_t> >(); + const Mesh *mesh = mesh_owner.getornull(p_mesh); + ERR_FAIL_COND_V(!mesh, Vector<PoolVector<uint8_t> >()); + ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<PoolVector<uint8_t> >()); +#ifndef TOOLS_ENABLED + ERR_PRINT("OpenGL ES 2.0 does not allow retrieving mesh array data"); +#endif + + return mesh->surfaces[p_surface]->blend_shape_data; } Vector<AABB> RasterizerStorageGLES2::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const { const Mesh *mesh = mesh_owner.getornull(p_mesh); @@ -2111,7 +2670,7 @@ void RasterizerStorageGLES2::mesh_remove_surface(RID p_mesh, int p_surface) { Surface *surface = mesh->surfaces[p_surface]; if (surface->material.is_valid()) { - // TODO _material_remove_geometry(surface->material, mesh->surfaces[p_surface]); + _material_remove_geometry(surface->material, mesh->surfaces[p_surface]); } glDeleteBuffers(1, &surface->vertex_id); @@ -2125,13 +2684,11 @@ void RasterizerStorageGLES2::mesh_remove_surface(RID p_mesh, int p_surface) { info.vertex_mem -= surface->total_data_size; - mesh->instance_material_change_notify(); - memdelete(surface); mesh->surfaces.remove(p_surface); - mesh->instance_change_notify(); + mesh->instance_change_notify(true, true); } int RasterizerStorageGLES2::mesh_get_surface_count(RID p_mesh) const { @@ -2161,16 +2718,110 @@ AABB RasterizerStorageGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { if (mesh->custom_aabb != AABB()) return mesh->custom_aabb; - // TODO handle skeletons + Skeleton *sk = NULL; + if (p_skeleton.is_valid()) { + sk = skeleton_owner.get(p_skeleton); + } AABB aabb; - if (mesh->surfaces.size() >= 1) { - aabb = mesh->surfaces[0]->aabb; - } + if (sk && sk->size != 0) { + + for (int i = 0; i < mesh->surfaces.size(); i++) { + + AABB laabb; + if ((mesh->surfaces[i]->format & VS::ARRAY_FORMAT_BONES) && mesh->surfaces[i]->skeleton_bone_aabb.size()) { + + int bs = mesh->surfaces[i]->skeleton_bone_aabb.size(); + const AABB *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr(); + const bool *skused = mesh->surfaces[i]->skeleton_bone_used.ptr(); + + int sbs = sk->size; + ERR_CONTINUE(bs > sbs); + const float *texture = sk->bone_data.ptr(); + + bool first = true; + if (sk->use_2d) { + for (int j = 0; j < bs; j++) { + + if (!skused[j]) + continue; + + int base_ofs = j * 2 * 4; + + Transform mtx; + + mtx.basis[0].x = texture[base_ofs + 0]; + mtx.basis[0].y = texture[base_ofs + 1]; + mtx.origin.x = texture[base_ofs + 3]; + base_ofs += 4; + mtx.basis[1].x = texture[base_ofs + 0]; + mtx.basis[1].y = texture[base_ofs + 1]; + mtx.origin.y = texture[base_ofs + 3]; + + AABB baabb = mtx.xform(skbones[j]); - for (int i = 0; i < mesh->surfaces.size(); i++) { - aabb.merge_with(mesh->surfaces[i]->aabb); + if (first) { + laabb = baabb; + first = false; + } else { + laabb.merge_with(baabb); + } + } + } else { + for (int j = 0; j < bs; j++) { + + if (!skused[j]) + continue; + + int base_ofs = j * 3 * 4; + + Transform mtx; + + mtx.basis[0].x = texture[base_ofs + 0]; + mtx.basis[0].y = texture[base_ofs + 1]; + mtx.basis[0].z = texture[base_ofs + 2]; + mtx.origin.x = texture[base_ofs + 3]; + base_ofs += 4; + mtx.basis[1].x = texture[base_ofs + 0]; + mtx.basis[1].y = texture[base_ofs + 1]; + mtx.basis[1].z = texture[base_ofs + 2]; + mtx.origin.y = texture[base_ofs + 3]; + base_ofs += 4; + mtx.basis[2].x = texture[base_ofs + 0]; + mtx.basis[2].y = texture[base_ofs + 1]; + mtx.basis[2].z = texture[base_ofs + 2]; + mtx.origin.z = texture[base_ofs + 3]; + + AABB baabb = mtx.xform(skbones[j]); + if (first) { + laabb = baabb; + first = false; + } else { + laabb.merge_with(baabb); + } + } + } + + } else { + + laabb = mesh->surfaces[i]->aabb; + } + + if (i == 0) + aabb = laabb; + else + aabb.merge_with(laabb); + } + } else { + + for (int i = 0; i < mesh->surfaces.size(); i++) { + + if (i == 0) + aabb = mesh->surfaces[i]->aabb; + else + aabb.merge_with(mesh->surfaces[i]->aabb); + } } return aabb; @@ -2636,10 +3287,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(); @@ -2705,7 +3356,7 @@ void RasterizerStorageGLES2::update_dirty_multimeshes() { multimesh->dirty_aabb = false; multimesh->dirty_data = false; - multimesh->instance_change_notify(); + multimesh->instance_change_notify(true, false); multimesh_update_list.remove(multimesh_update_list.first()); } @@ -2810,7 +3461,7 @@ void RasterizerStorageGLES2::immediate_end(RID p_immediate) { ERR_FAIL_COND(!im->building); im->building = false; - im->instance_change_notify(); + im->instance_change_notify(true, false); } void RasterizerStorageGLES2::immediate_clear(RID p_immediate) { @@ -2819,7 +3470,7 @@ void RasterizerStorageGLES2::immediate_clear(RID p_immediate) { ERR_FAIL_COND(im->building); im->chunks.clear(); - im->instance_change_notify(); + im->instance_change_notify(true, false); } AABB RasterizerStorageGLES2::immediate_get_aabb(RID p_immediate) const { @@ -2833,7 +3484,7 @@ void RasterizerStorageGLES2::immediate_set_material(RID p_immediate, RID p_mater ERR_FAIL_COND(!im); im->material = p_material; - im->instance_material_change_notify(); + im->instance_change_notify(false, true); } RID RasterizerStorageGLES2::immediate_get_material(RID p_immediate) const { @@ -2848,6 +3499,8 @@ RID RasterizerStorageGLES2::skeleton_create() { Skeleton *skeleton = memnew(Skeleton); + glGenTextures(1, &skeleton->tex_id); + return skeleton_owner.make_rid(skeleton); } @@ -2864,17 +3517,15 @@ void RasterizerStorageGLES2::skeleton_allocate(RID p_skeleton, int p_bones, bool skeleton->size = p_bones; skeleton->use_2d = p_2d_skeleton; - // TODO use float texture for vertex shader - if (config.float_texture_supported) { - glGenTextures(1, &skeleton->tex_id); + if (!config.use_skeleton_software) { glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); #ifdef GLES_OVER_GL - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_bones * 3, 1, 0, GL_RGBA, GL_FLOAT, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_bones * (skeleton->use_2d ? 2 : 3), 1, 0, GL_RGBA, GL_FLOAT, NULL); #else - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_bones * 3, 1, 0, GL_RGBA, GL_FLOAT, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_bones * (skeleton->use_2d ? 2 : 3), 1, 0, GL_RGBA, GL_FLOAT, NULL); #endif glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -3008,6 +3659,11 @@ Transform2D RasterizerStorageGLES2::skeleton_bone_get_transform_2d(RID p_skeleto } void RasterizerStorageGLES2::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + + skeleton->base_transform_2d = p_base_transform; } void RasterizerStorageGLES2::_update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size) { @@ -3029,7 +3685,7 @@ void RasterizerStorageGLES2::_update_skeleton_transform_buffer(const PoolVector< void RasterizerStorageGLES2::update_dirty_skeletons() { - if (!config.float_texture_supported) + if (config.use_skeleton_software) return; glActiveTexture(GL_TEXTURE0); @@ -3040,11 +3696,11 @@ void RasterizerStorageGLES2::update_dirty_skeletons() { if (skeleton->size) { glBindTexture(GL_TEXTURE_2D, skeleton->tex_id); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, skeleton->size * 3, 1, GL_RGBA, GL_FLOAT, skeleton->bone_data.ptr()); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, skeleton->size * (skeleton->use_2d ? 2 : 3), 1, GL_RGBA, GL_FLOAT, skeleton->bone_data.ptr()); } for (Set<RasterizerScene::InstanceBase *>::Element *E = skeleton->instances.front(); E; E = E->next()) { - E->get()->base_changed(); + E->get()->base_changed(true, false); } skeleton_update_list.remove(skeleton_update_list.first()); @@ -3082,6 +3738,7 @@ RID RasterizerStorageGLES2::light_create(VS::LightType p_type) { light->directional_blend_splits = false; light->directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; light->reverse_cull = false; + light->use_gi = true; light->version = 0; return light_owner.make_rid(light); @@ -3109,8 +3766,10 @@ void RasterizerStorageGLES2::light_set_param(RID p_light, VS::LightParam p_param case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: case VS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } break; + default: { + } } light->param[p_param] = p_value; @@ -3123,7 +3782,7 @@ void RasterizerStorageGLES2::light_set_shadow(RID p_light, bool p_enabled) { light->shadow = p_enabled; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_set_shadow_color(RID p_light, const Color &p_color) { @@ -3154,7 +3813,7 @@ void RasterizerStorageGLES2::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->cull_mask = p_mask; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { @@ -3162,6 +3821,19 @@ 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(true, false); +} + +void RasterizerStorageGLES2::light_set_use_gi(RID p_light, bool p_enabled) { + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->use_gi = p_enabled; + + light->version++; + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) { @@ -3171,7 +3843,7 @@ void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOm light->omni_shadow_mode = p_mode; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } VS::LightOmniShadowMode RasterizerStorageGLES2::light_omni_get_shadow_mode(RID p_light) { @@ -3188,7 +3860,7 @@ void RasterizerStorageGLES2::light_omni_set_shadow_detail(RID p_light, VS::Light light->omni_shadow_detail = p_detail; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) { @@ -3198,7 +3870,7 @@ void RasterizerStorageGLES2::light_directional_set_shadow_mode(RID p_light, VS:: light->directional_shadow_mode = p_mode; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_directional_set_blend_splits(RID p_light, bool p_enable) { @@ -3208,7 +3880,7 @@ void RasterizerStorageGLES2::light_directional_set_blend_splits(RID p_light, boo light->directional_blend_splits = p_enable; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } bool RasterizerStorageGLES2::light_directional_get_blend_splits(RID p_light) const { @@ -3259,6 +3931,13 @@ Color RasterizerStorageGLES2::light_get_color(RID p_light) { return light->color; } +bool RasterizerStorageGLES2::light_get_use_gi(RID p_light) { + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, false); + + return light->use_gi; +} + bool RasterizerStorageGLES2::light_has_shadow(RID p_light) const { Light *light = light_owner.getornull(p_light); ERR_FAIL_COND_V(!light, false); @@ -3283,88 +3962,214 @@ AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const { float len = light->param[VS::LIGHT_PARAM_RANGE]; float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len; return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); - } break; + }; case VS::LIGHT_OMNI: { float r = light->param[VS::LIGHT_PARAM_RANGE]; return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2); - } break; + }; case VS::LIGHT_DIRECTIONAL: { return AABB(); - } break; + }; } ERR_FAIL_V(AABB()); - return AABB(); } /* 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->interior_ambient_probe_contrib = 0.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(true, false); } 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(true, false); } +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(true, false); +} 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(true, false); } 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; + reflection_probe->instance_change_notify(true, false); +} 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(true, false); +} 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(true, false); +} + +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() { @@ -3465,46 +4270,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(true, false); } +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(true, false); +} 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; } /////// @@ -3593,109 +4452,332 @@ RID RasterizerStorageGLES2::particles_get_draw_pass_mesh(RID p_particles, int p_ void RasterizerStorageGLES2::update_particles() { } +bool RasterizerStorageGLES2::particles_is_inactive(RID p_particles) const { + return true; +} + //////// 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: { + 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: { + ERR_FAIL(); + } + } + + inst->instance_list.remove(&p_instance->dependency_item); } /* RENDER TARGET */ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { + // do not allocate a render target with no size if (rt->width <= 0 || rt->height <= 0) return; - Texture *texture = texture_owner.getornull(rt->texture); - ERR_FAIL_COND(!texture); + // do not allocate a render target that is attached to the screen + if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { + rt->fbo = RasterizerStorageGLES2::system_fbo; + return; + } - // create fbo + GLuint color_internal_format; + GLuint color_format; + GLuint color_type = GL_UNSIGNED_BYTE; - glGenFramebuffers(1, &rt->fbo); - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); + if (rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + color_internal_format = GL_RGBA; + color_format = GL_RGBA; + } else { + color_internal_format = GL_RGB; + color_format = GL_RGB; + } - // color + rt->used_dof_blur_near = false; + rt->mip_maps_allocated = false; - glGenTextures(1, &rt->color); - glBindTexture(GL_TEXTURE_2D, rt->color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + { - if (texture->flags & VS::TEXTURE_FLAG_FILTER) { + /* Front FBO */ - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - } else { + Texture *texture = texture_owner.getornull(rt->texture); + ERR_FAIL_COND(!texture); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - } - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + // framebuffer + glGenFramebuffers(1, &rt->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + // color + glGenTextures(1, &rt->color); + glBindTexture(GL_TEXTURE_2D, rt->color); - // depth + glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); - glGenRenderbuffers(1, &rt->depth); - glBindRenderbuffer(GL_RENDERBUFFER, rt->depth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, rt->width, rt->height); - glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + if (texture->flags & VS::TEXTURE_FLAG_FILTER) { - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + } else { - if (status != GL_FRAMEBUFFER_COMPLETE) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + } - glDeleteRenderbuffers(1, &rt->fbo); - glDeleteTextures(1, &rt->depth); - glDeleteTextures(1, &rt->color); - rt->fbo = 0; - rt->width = 0; - rt->height = 0; - rt->color = 0; - rt->depth = 0; - texture->tex_id = 0; - texture->active = false; - WARN_PRINT("Could not create framebuffer!!"); - return; + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + + // depth + + if (config.support_depth_texture) { + + glGenTextures(1, &rt->depth); + glBindTexture(GL_TEXTURE_2D, rt->depth); + glTexImage2D(GL_TEXTURE_2D, 0, config.depth_internalformat, rt->width, rt->height, 0, GL_DEPTH_COMPONENT, config.depth_type, NULL); + + 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); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + } else { + + glGenRenderbuffers(1, &rt->depth); + glBindRenderbuffer(GL_RENDERBUFFER, rt->depth); + + glRenderbufferStorage(GL_RENDERBUFFER, config.depth_internalformat, rt->width, rt->height); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + + glDeleteFramebuffers(1, &rt->fbo); + if (config.support_depth_texture) { + + glDeleteTextures(1, &rt->depth); + } else { + + glDeleteRenderbuffers(1, &rt->depth); + } + + glDeleteTextures(1, &rt->color); + rt->fbo = 0; + rt->width = 0; + rt->height = 0; + rt->color = 0; + rt->depth = 0; + texture->tex_id = 0; + texture->active = false; + WARN_PRINT("Could not create framebuffer!!"); + return; + } + + texture->format = Image::FORMAT_RGBA8; + texture->gl_format_cache = GL_RGBA; + texture->gl_type_cache = GL_UNSIGNED_BYTE; + texture->gl_internal_format_cache = GL_RGBA; + texture->tex_id = rt->color; + texture->width = rt->width; + texture->alloc_width = rt->width; + texture->height = rt->height; + texture->alloc_height = rt->height; + texture->active = true; + + texture_set_flags(rt->texture, texture->flags); } - texture->format = Image::FORMAT_RGBA8; - texture->gl_format_cache = GL_RGBA; - texture->gl_type_cache = GL_UNSIGNED_BYTE; - texture->gl_internal_format_cache = GL_RGBA; - texture->tex_id = rt->color; - texture->width = rt->width; - texture->alloc_width = rt->width; - texture->height = rt->height; - texture->alloc_height = rt->height; - texture->active = true; + /* BACK FBO */ + /* For MSAA */ + +#ifndef JAVASCRIPT_ENABLED + if (rt->msaa != VS::VIEWPORT_MSAA_DISABLED && config.multisample_supported) { + + rt->multisample_active = true; + + static const int msaa_value[] = { 0, 2, 4, 8, 16 }; + int msaa = msaa_value[rt->msaa]; + + int max_samples = 0; + glGetIntegerv(GL_MAX_SAMPLES, &max_samples); + if (msaa > max_samples) { + WARN_PRINTS("MSAA must be <= GL_MAX_SAMPLES, falling-back to GL_MAX_SAMPLES = " + itos(max_samples)); + msaa = max_samples; + } + + //regular fbo + glGenFramebuffers(1, &rt->multisample_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->multisample_fbo); + + glGenRenderbuffers(1, &rt->multisample_depth); + glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_depth); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, config.depth_internalformat, rt->width, rt->height); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->multisample_depth); + +#if defined(GLES_OVER_GL) || defined(IPHONE_ENABLED) + + glGenRenderbuffers(1, &rt->multisample_color); + glBindRenderbuffer(GL_RENDERBUFFER, rt->multisample_color); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, color_internal_format, rt->width, rt->height); + + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, rt->multisample_color); +#elif ANDROID_ENABLED + // Render to a texture in android + glGenTextures(1, &rt->multisample_color); + glBindTexture(GL_TEXTURE_2D, rt->multisample_color); + + glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, rt->width, rt->height, 0, color_format, color_type, NULL); + + // multisample buffer is same size as front buffer, so just use nearest + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + + glFramebufferTexture2DMultisample(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0, msaa); +#endif + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + printf("err status: %x\n", status); + _render_target_clear(rt); + ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); + } - texture_set_flags(rt->texture, texture->flags); + glBindRenderbuffer(GL_RENDERBUFFER, 0); + + } else +#endif + { + rt->multisample_active = false; + } glClearColor(0, 0, 0, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // copy texscreen buffers - { - int w = rt->width; - int h = rt->height; + if (!(rt->flags[RasterizerStorage::RENDER_TARGET_NO_SAMPLING])) { glGenTextures(1, &rt->copy_screen_effect.color); glBindTexture(GL_TEXTURE_2D, rt->copy_screen_effect.color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + if (rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, rt->width, rt->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, rt->width, rt->height, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glGenFramebuffers(1, &rt->copy_screen_effect.fbo); glBindFramebuffer(GL_FRAMEBUFFER, rt->copy_screen_effect.fbo); - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->color, 0); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->copy_screen_effect.color, 0); + + glClearColor(0, 0, 0, 0); + glClear(GL_COLOR_BUFFER_BIT); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); if (status != GL_FRAMEBUFFER_COMPLETE) { @@ -3704,19 +4786,165 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { } } + // Allocate mipmap chains for post_process effects + if (!rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D] && rt->width >= 2 && rt->height >= 2) { + + for (int i = 0; i < 2; i++) { + + ERR_FAIL_COND(rt->mip_maps[i].sizes.size()); + int w = rt->width; + int h = rt->height; + + if (i > 0) { + w >>= 1; + h >>= 1; + } + + int level = 0; + int fb_w = w; + int fb_h = h; + + while (true) { + + RenderTarget::MipMaps::Size mm; + mm.width = w; + mm.height = h; + rt->mip_maps[i].sizes.push_back(mm); + + w >>= 1; + h >>= 1; + + if (w < 2 || h < 2) + break; + + level++; + } + + GLsizei width = fb_w; + GLsizei height = fb_h; + + if (config.render_to_mipmap_supported) { + + glGenTextures(1, &rt->mip_maps[i].color); + glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].color); + + for (int l = 0; l < level + 1; l++) { + glTexImage2D(GL_TEXTURE_2D, l, color_internal_format, width, height, 0, color_format, color_type, NULL); + width = MAX(1, (width / 2)); + height = MAX(1, (height / 2)); + } +#ifdef GLES_OVER_GL + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_BASE_LEVEL, 0); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); +#endif + } else { + + // Can't render to specific levels of a mipmap in ES 2.0 or Webgl so create a texture for each level + for (int l = 0; l < level + 1; l++) { + glGenTextures(1, &rt->mip_maps[i].sizes.write[l].color); + glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[l].color); + glTexImage2D(GL_TEXTURE_2D, 0, color_internal_format, width, height, 0, color_format, color_type, NULL); + width = MAX(1, (width / 2)); + height = MAX(1, (height / 2)); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + } + + glDisable(GL_SCISSOR_TEST); + glColorMask(1, 1, 1, 1); + glDepthMask(GL_TRUE); + + for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { + + RenderTarget::MipMaps::Size &mm = rt->mip_maps[i].sizes.write[j]; + + glGenFramebuffers(1, &mm.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, mm.fbo); + + if (config.render_to_mipmap_supported) { + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].color, j); + } else { + + glBindTexture(GL_TEXTURE_2D, rt->mip_maps[i].sizes[j].color); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->mip_maps[i].sizes[j].color, 0); + } + + bool used_depth = false; + if (j == 0 && i == 0) { //use always + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + used_depth = true; + } + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + WARN_PRINT_ONCE("Cannot allocate mipmaps for 3D post processing effects"); + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); + return; + } + + glClearColor(1.0, 0.0, 1.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + if (used_depth) { + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); + } + } + + rt->mip_maps[i].levels = level; + + if (config.render_to_mipmap_supported) { + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + } + rt->mip_maps_allocated = true; + } + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); } void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) { + // there is nothing to clear when DIRECT_TO_SCREEN is used + if (rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) + return; + if (rt->fbo) { glDeleteFramebuffers(1, &rt->fbo); glDeleteTextures(1, &rt->color); rt->fbo = 0; } + if (rt->external.fbo != 0) { + // free this + glDeleteFramebuffers(1, &rt->external.fbo); + + // clean up our texture + Texture *t = texture_owner.get(rt->external.texture); + t->alloc_height = 0; + t->alloc_width = 0; + t->width = 0; + t->height = 0; + t->active = false; + texture_owner.free(rt->external.texture); + memdelete(t); + + rt->external.fbo = 0; + } + if (rt->depth) { - glDeleteRenderbuffers(1, &rt->depth); + if (config.support_depth_texture) { + glDeleteTextures(1, &rt->depth); + } else { + glDeleteRenderbuffers(1, &rt->depth); + } + rt->depth = 0; } @@ -3727,7 +4955,6 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) { tex->height = 0; tex->active = false; - // TODO hardcoded texscreen copy effect if (rt->copy_screen_effect.color) { glDeleteFramebuffers(1, &rt->copy_screen_effect.fbo); rt->copy_screen_effect.fbo = 0; @@ -3735,6 +4962,34 @@ void RasterizerStorageGLES2::_render_target_clear(RenderTarget *rt) { glDeleteTextures(1, &rt->copy_screen_effect.color); rt->copy_screen_effect.color = 0; } + + for (int i = 0; i < 2; i++) { + if (rt->mip_maps[i].sizes.size()) { + for (int j = 0; j < rt->mip_maps[i].sizes.size(); j++) { + glDeleteFramebuffers(1, &rt->mip_maps[i].sizes[j].fbo); + glDeleteTextures(1, &rt->mip_maps[i].sizes[j].color); + } + + glDeleteTextures(1, &rt->mip_maps[i].color); + rt->mip_maps[i].sizes.clear(); + rt->mip_maps[i].levels = 0; + rt->mip_maps[i].color = 0; + } + } + + if (rt->multisample_active) { + glDeleteFramebuffers(1, &rt->multisample_fbo); + rt->multisample_fbo = 0; + + glDeleteRenderbuffers(1, &rt->multisample_depth); + rt->multisample_depth = 0; +#ifdef GLES_OVER_GL + glDeleteRenderbuffers(1, &rt->multisample_color); +#else + glDeleteTextures(1, &rt->multisample_color); +#endif + rt->multisample_color = 0; + } } RID RasterizerStorageGLES2::render_target_create() { @@ -3743,6 +4998,7 @@ RID RasterizerStorageGLES2::render_target_create() { Texture *t = memnew(Texture); + t->type = VS::TEXTURE_TYPE_2D; t->flags = 0; t->width = 0; t->height = 0; @@ -3767,6 +5023,15 @@ RID RasterizerStorageGLES2::render_target_create() { return render_target_owner.make_rid(rt); } +void RasterizerStorageGLES2::render_target_set_position(RID p_render_target, int p_x, int p_y) { + + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + rt->x = p_x; + rt->y = p_y; +} + void RasterizerStorageGLES2::render_target_set_size(RID p_render_target, int p_width, int p_height) { RenderTarget *rt = render_target_owner.getornull(p_render_target); @@ -3788,16 +5053,126 @@ RID RasterizerStorageGLES2::render_target_get_texture(RID p_render_target) const RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); - return rt->texture; + if (rt->external.fbo == 0) { + return rt->texture; + } else { + return rt->external.texture; + } +} + +void RasterizerStorageGLES2::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + if (p_texture_id == 0) { + if (rt->external.fbo != 0) { + // free this + glDeleteFramebuffers(1, &rt->external.fbo); + + // clean up our texture + Texture *t = texture_owner.get(rt->external.texture); + t->alloc_height = 0; + t->alloc_width = 0; + t->width = 0; + t->height = 0; + t->active = false; + texture_owner.free(rt->external.texture); + memdelete(t); + + rt->external.fbo = 0; + rt->external.color = 0; + } + } else { + Texture *t; + + if (rt->external.fbo == 0) { + // create our fbo + glGenFramebuffers(1, &rt->external.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); + + // allocate a texture + t = memnew(Texture); + + t->type = VS::TEXTURE_TYPE_2D; + t->flags = 0; + t->width = 0; + t->height = 0; + t->alloc_height = 0; + t->alloc_width = 0; + t->format = Image::FORMAT_RGBA8; + t->target = GL_TEXTURE_2D; + t->gl_format_cache = 0; + t->gl_internal_format_cache = 0; + t->gl_type_cache = 0; + t->data_size = 0; + t->compressed = false; + t->srgb = false; + t->total_data_size = 0; + t->ignore_mipmaps = false; + t->mipmaps = 1; + t->active = true; + t->tex_id = 0; + t->render_target = rt; + + rt->external.texture = texture_owner.make_rid(t); + } else { + // bind our frame buffer + glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); + + // find our texture + t = texture_owner.get(rt->external.texture); + } + + // set our texture + t->tex_id = p_texture_id; + rt->external.color = p_texture_id; + + // size shouldn't be different + t->width = rt->width; + t->height = rt->height; + t->alloc_height = rt->width; + t->alloc_width = rt->height; + + // is there a point to setting the internal formats? we don't know them.. + + // set our texture as the destination for our framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0); + + // seeing we're rendering into this directly, better also use our depth buffer, just use our existing one :) + if (config.support_depth_texture) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, rt->depth, 0); + } else { + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); + } + + // check status and unbind + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + printf("framebuffer fail, status: %x\n", status); + } + + ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); + } } void RasterizerStorageGLES2::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND(!rt); + // When setting DIRECT_TO_SCREEN, you need to clear before the value is set, but allocate after as + // those functions change how they operate depending on the value of DIRECT_TO_SCREEN + if (p_flag == RENDER_TARGET_DIRECT_TO_SCREEN && p_value != rt->flags[RENDER_TARGET_DIRECT_TO_SCREEN]) { + _render_target_clear(rt); + rt->flags[p_flag] = p_value; + _render_target_allocate(rt); + } + rt->flags[p_flag] = p_value; switch (p_flag) { + case RENDER_TARGET_TRANSPARENT: case RENDER_TARGET_HDR: case RENDER_TARGET_NO_3D: case RENDER_TARGET_NO_SAMPLING: @@ -3807,7 +5182,8 @@ void RasterizerStorageGLES2::render_target_set_flag(RID p_render_target, RenderT _render_target_allocate(rt); } break; - default: {} + default: { + } } } @@ -3832,6 +5208,11 @@ void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, VS::Vie if (rt->msaa == p_msaa) return; + if (!config.multisample_supported) { + ERR_PRINT("MSAA not supported on this hardware."); + return; + } + _render_target_clear(rt); rt->msaa = p_msaa; _render_target_allocate(rt); @@ -3840,16 +5221,158 @@ void RasterizerStorageGLES2::render_target_set_msaa(RID p_render_target, VS::Vie /* CANVAS SHADOW */ RID RasterizerStorageGLES2::canvas_light_shadow_buffer_create(int p_width) { - return RID(); + + CanvasLightShadow *cls = memnew(CanvasLightShadow); + + if (p_width > config.max_texture_size) + p_width = config.max_texture_size; + + cls->size = p_width; + cls->height = 16; + + glActiveTexture(GL_TEXTURE0); + + glGenFramebuffers(1, &cls->fbo); + glBindFramebuffer(GL_FRAMEBUFFER, cls->fbo); + + glGenRenderbuffers(1, &cls->depth); + glBindRenderbuffer(GL_RENDERBUFFER, cls->depth); + glRenderbufferStorage(GL_RENDERBUFFER, config.depth_internalformat, cls->size, cls->height); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, cls->depth); + + glGenTextures(1, &cls->distance); + glBindTexture(GL_TEXTURE_2D, cls->distance); + if (config.use_rgba_2d_shadows) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, cls->size, cls->height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + } else { +#ifdef GLES_OVER_GL + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, NULL); +#else + glTexImage2D(GL_TEXTURE_2D, 0, GL_FLOAT, cls->size, cls->height, 0, _RED_OES, GL_FLOAT, NULL); +#endif + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, cls->distance, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + //printf("errnum: %x\n",status); + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + memdelete(cls); + ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID()); + } + + return canvas_light_shadow_owner.make_rid(cls); } /* LIGHT SHADOW MAPPING */ RID RasterizerStorageGLES2::canvas_light_occluder_create() { - return RID(); + + CanvasOccluder *co = memnew(CanvasOccluder); + co->index_id = 0; + co->vertex_id = 0; + co->len = 0; + + return canvas_occluder_owner.make_rid(co); } void RasterizerStorageGLES2::canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines) { + + CanvasOccluder *co = canvas_occluder_owner.get(p_occluder); + ERR_FAIL_COND(!co); + + co->lines = p_lines; + + if (p_lines.size() != co->len) { + + if (co->index_id) + glDeleteBuffers(1, &co->index_id); + if (co->vertex_id) + glDeleteBuffers(1, &co->vertex_id); + + co->index_id = 0; + co->vertex_id = 0; + co->len = 0; + } + + if (p_lines.size()) { + + PoolVector<float> geometry; + PoolVector<uint16_t> indices; + int lc = p_lines.size(); + + geometry.resize(lc * 6); + indices.resize(lc * 3); + + PoolVector<float>::Write vw = geometry.write(); + PoolVector<uint16_t>::Write iw = indices.write(); + + PoolVector<Vector2>::Read lr = p_lines.read(); + + const int POLY_HEIGHT = 16384; + + for (int i = 0; i < lc / 2; i++) { + + vw[i * 12 + 0] = lr[i * 2 + 0].x; + vw[i * 12 + 1] = lr[i * 2 + 0].y; + vw[i * 12 + 2] = POLY_HEIGHT; + + vw[i * 12 + 3] = lr[i * 2 + 1].x; + vw[i * 12 + 4] = lr[i * 2 + 1].y; + vw[i * 12 + 5] = POLY_HEIGHT; + + vw[i * 12 + 6] = lr[i * 2 + 1].x; + vw[i * 12 + 7] = lr[i * 2 + 1].y; + vw[i * 12 + 8] = -POLY_HEIGHT; + + vw[i * 12 + 9] = lr[i * 2 + 0].x; + vw[i * 12 + 10] = lr[i * 2 + 0].y; + vw[i * 12 + 11] = -POLY_HEIGHT; + + iw[i * 6 + 0] = i * 4 + 0; + iw[i * 6 + 1] = i * 4 + 1; + iw[i * 6 + 2] = i * 4 + 2; + + iw[i * 6 + 3] = i * 4 + 2; + iw[i * 6 + 4] = i * 4 + 3; + iw[i * 6 + 5] = i * 4 + 0; + } + + //if same buffer len is being set, just use BufferSubData to avoid a pipeline flush + + if (!co->vertex_id) { + glGenBuffers(1, &co->vertex_id); + glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); + glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); + } else { + + glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); + glBufferSubData(GL_ARRAY_BUFFER, 0, lc * 6 * sizeof(real_t), vw.ptr()); + } + + glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind + + if (!co->index_id) { + + glGenBuffers(1, &co->index_id); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, lc * 3 * sizeof(uint16_t), iw.ptr(), GL_DYNAMIC_DRAW); + } else { + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, co->index_id); + glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, lc * 3 * sizeof(uint16_t), iw.ptr()); + } + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); //unbind + + co->len = lc; + } } VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const { @@ -3862,6 +5385,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; } @@ -3904,7 +5431,7 @@ bool RasterizerStorageGLES2::free(RID p_rid) { Shader *shader = shader_owner.get(p_rid); - if (shader->shader) { + if (shader->shader && shader->custom_code_id) { shader->shader->free_custom_shader(shader->custom_code_id); } @@ -4039,6 +5566,49 @@ 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 if (canvas_occluder_owner.owns(p_rid)) { + + CanvasOccluder *co = canvas_occluder_owner.get(p_rid); + if (co->index_id) + glDeleteBuffers(1, &co->index_id); + if (co->vertex_id) + glDeleteBuffers(1, &co->vertex_id); + + canvas_occluder_owner.free(p_rid); + memdelete(co); + + return true; + + } else if (canvas_light_shadow_owner.owns(p_rid)) { + + CanvasLightShadow *cls = canvas_light_shadow_owner.get(p_rid); + glDeleteFramebuffers(1, &cls->fbo); + glDeleteRenderbuffers(1, &cls->depth); + glDeleteTextures(1, &cls->distance); + canvas_light_shadow_owner.free(p_rid); + memdelete(cls); + + return true; } else { return false; } @@ -4046,6 +5616,9 @@ bool RasterizerStorageGLES2::free(RID p_rid) { bool RasterizerStorageGLES2::has_os_feature(const String &p_feature) const { + if (p_feature == "pvrtc") + return config.pvrtc_supported; + if (p_feature == "s3tc") return config.s3tc_supported; @@ -4061,18 +5634,72 @@ void RasterizerStorageGLES2::set_debug_generate_wireframes(bool p_generate) { } void RasterizerStorageGLES2::render_info_begin_capture() { + + info.snap = info.render; } void RasterizerStorageGLES2::render_info_end_capture() { + + info.snap.object_count = info.render.object_count - info.snap.object_count; + info.snap.draw_call_count = info.render.draw_call_count - info.snap.draw_call_count; + info.snap.material_switch_count = info.render.material_switch_count - info.snap.material_switch_count; + info.snap.surface_switch_count = info.render.surface_switch_count - info.snap.surface_switch_count; + info.snap.shader_rebind_count = info.render.shader_rebind_count - info.snap.shader_rebind_count; + info.snap.vertices_count = info.render.vertices_count - info.snap.vertices_count; } int RasterizerStorageGLES2::get_captured_render_info(VS::RenderInfo p_info) { - return get_render_info(p_info); + switch (p_info) { + case VS::INFO_OBJECTS_IN_FRAME: { + return info.snap.object_count; + } break; + case VS::INFO_VERTICES_IN_FRAME: { + return info.snap.vertices_count; + } break; + case VS::INFO_MATERIAL_CHANGES_IN_FRAME: { + return info.snap.material_switch_count; + } break; + case VS::INFO_SHADER_CHANGES_IN_FRAME: { + return info.snap.shader_rebind_count; + } break; + case VS::INFO_SURFACE_CHANGES_IN_FRAME: { + return info.snap.surface_switch_count; + } break; + case VS::INFO_DRAW_CALLS_IN_FRAME: { + return info.snap.draw_call_count; + } break; + default: { + return get_render_info(p_info); + } + } } int RasterizerStorageGLES2::get_render_info(VS::RenderInfo p_info) { - return 0; + switch (p_info) { + case VS::INFO_OBJECTS_IN_FRAME: + return info.render_final.object_count; + case VS::INFO_VERTICES_IN_FRAME: + return info.render_final.vertices_count; + case VS::INFO_MATERIAL_CHANGES_IN_FRAME: + return info.render_final.material_switch_count; + case VS::INFO_SHADER_CHANGES_IN_FRAME: + return info.render_final.shader_rebind_count; + case VS::INFO_SURFACE_CHANGES_IN_FRAME: + return info.render_final.surface_switch_count; + case VS::INFO_DRAW_CALLS_IN_FRAME: + return info.render_final.draw_call_count; + case VS::INFO_USAGE_VIDEO_MEM_TOTAL: + return 0; //no idea + case VS::INFO_VIDEO_MEM_USED: + return info.vertex_mem + info.texture_mem; + case VS::INFO_TEXTURE_MEM_USED: + return info.texture_mem; + case VS::INFO_VERTEX_MEM_USED: + return info.vertex_mem; + default: + return 0; //no idea either + } } void RasterizerStorageGLES2::initialize() { @@ -4089,22 +5716,183 @@ void RasterizerStorageGLES2::initialize() { } } + config.keep_original_textures = false; 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; + +#ifdef GLES_OVER_GL + config.float_texture_supported = true; + config.s3tc_supported = true; + config.pvrtc_supported = false; + config.etc1_supported = false; + config.support_npot_repeat_mipmap = true; + config.depth_internalformat = GL_DEPTH_COMPONENT; + config.depth_type = GL_UNSIGNED_INT; + +#else + 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.extensions.has("WEBGL_compressed_texture_s3tc"); + config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") || config.extensions.has("WEBGL_compressed_texture_etc1"); + config.pvrtc_supported = config.extensions.has("IMG_texture_compression_pvrtc"); + config.support_npot_repeat_mipmap = config.extensions.has("GL_OES_texture_npot"); + +#endif + +#ifndef GLES_OVER_GL + //Manually load extensions for android and ios + +#ifdef IPHONE_ENABLED + // appears that IPhone doesn't need to dlopen TODO: test this rigorously before removing + //void *gles2_lib = dlopen(NULL, RTLD_LAZY); + //glRenderbufferStorageMultisampleAPPLE = dlsym(gles2_lib, "glRenderbufferStorageMultisampleAPPLE"); + //glResolveMultisampleFramebufferAPPLE = dlsym(gles2_lib, "glResolveMultisampleFramebufferAPPLE"); +#elif ANDROID_ENABLED + + void *gles2_lib = dlopen("libGLESv2.so", RTLD_LAZY); + glRenderbufferStorageMultisampleEXT = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glRenderbufferStorageMultisampleEXT"); + glFramebufferTexture2DMultisampleEXT = (PFNGLFRAMEBUFFERTEXTURE2DMULTISAMPLEEXTPROC)dlsym(gles2_lib, "glFramebufferTexture2DMultisampleEXT"); +#endif +#endif + + // Check for multisample support + config.multisample_supported = config.extensions.has("GL_EXT_framebuffer_multisample") || config.extensions.has("GL_EXT_multisampled_render_to_texture") || config.extensions.has("GL_APPLE_framebuffer_multisample"); + +#ifdef GLES_OVER_GL + config.render_to_mipmap_supported = true; +#else + //check if mipmaps can be used for SCREEN_TEXTURE and Glow on Mobile and web platforms + config.render_to_mipmap_supported = config.extensions.has("GL_OES_fbo_render_mipmap") && config.extensions.has("GL_EXT_texture_lod"); +#endif + +#ifdef GLES_OVER_GL + config.use_rgba_2d_shadows = false; + config.support_depth_texture = true; + config.use_rgba_3d_shadows = false; + config.support_depth_cubemaps = true; +#else + config.use_rgba_2d_shadows = !(config.float_texture_supported && config.extensions.has("GL_EXT_texture_rg")); + config.support_depth_texture = config.extensions.has("GL_OES_depth_texture"); + config.use_rgba_3d_shadows = !config.support_depth_texture; + config.support_depth_cubemaps = config.extensions.has("GL_OES_depth_texture_cube_map"); +#endif + +#ifdef GLES_OVER_GL + config.support_32_bits_indices = true; +#else + config.support_32_bits_indices = config.extensions.has("GL_OES_element_index_uint"); +#endif + +#ifdef GLES_OVER_GL + config.support_write_depth = true; +#elif defined(JAVASCRIPT_ENABLED) + config.support_write_depth = false; +#else + config.support_write_depth = config.extensions.has("GL_EXT_frag_depth"); +#endif + +#ifdef JAVASCRIPT_ENABLED + config.support_half_float_vertices = false; +#else + //every other platform, be it mobile or desktop, supports this (even if not in the GLES2 spec). + config.support_half_float_vertices = true; +#endif + + config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc") || config.extensions.has("EXT_texture_compression_rgtc"); + config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc"); + + //determine formats for depth textures (or renderbuffers) + if (config.support_depth_texture) { + // Will use texture for depth + // have to manually see if we can create a valid framebuffer texture using UNSIGNED_INT, + // as there is no extension to test for this. + GLuint fbo; + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + GLuint depth; + glGenTextures(1, &depth); + glBindTexture(GL_TEXTURE_2D, depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, 32, 32, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + + 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); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); + + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + + glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); + glDeleteFramebuffers(1, &fbo); + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &depth); + + if (status == GL_FRAMEBUFFER_COMPLETE) { + config.depth_internalformat = GL_DEPTH_COMPONENT; + config.depth_type = GL_UNSIGNED_INT; + } else { + // If it fails, test to see if it supports a framebuffer texture using UNSIGNED_SHORT + // This is needed because many OSX devices don't support either UNSIGNED_INT or UNSIGNED_SHORT + + config.depth_internalformat = GL_DEPTH_COMPONENT16; + config.depth_type = GL_UNSIGNED_SHORT; + + glGenFramebuffers(1, &fbo); + glBindFramebuffer(GL_FRAMEBUFFER, fbo); + + glGenTextures(1, &depth); + glBindTexture(GL_TEXTURE_2D, depth); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT16, 32, 32, 0, GL_DEPTH_COMPONENT16, GL_UNSIGNED_SHORT, NULL); + + 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); + + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, depth, 0); + + status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + if (status != GL_FRAMEBUFFER_COMPLETE) { + //if it fails again depth textures aren't supported, use rgba shadows and renderbuffer for depth + config.support_depth_texture = false; + config.use_rgba_3d_shadows = true; + } + + glBindFramebuffer(GL_FRAMEBUFFER, system_fbo); + glDeleteFramebuffers(1, &fbo); + glBindTexture(GL_TEXTURE_2D, 0); + glDeleteTextures(1, &depth); + } + } else { + // Will use renderbuffer for depth, on mobile check for 24 bit depth support + if (config.extensions.has("GL_OES_depth24")) { + config.depth_internalformat = _DEPTH_COMPONENT24_OES; + config.depth_type = GL_UNSIGNED_INT; + } else { + config.depth_internalformat = GL_DEPTH_COMPONENT16; + config.depth_type = GL_UNSIGNED_SHORT; + } + } + + //picky requirements for these + config.support_shadow_cubemaps = config.support_depth_texture && config.support_write_depth && config.support_depth_cubemaps; frame.count = 0; frame.delta = 0; frame.current_rt = NULL; frame.clear_request = false; - // config.keep_original_textures = false; + glGetIntegerv(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &config.max_vertex_texture_image_units); glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); + // the use skeleton software path should be used if either float texture is not supported, + // OR max_vertex_texture_image_units is zero + config.use_skeleton_software = (config.float_texture_supported == false) || (config.max_vertex_texture_image_units == 0); + shaders.copy.init(); shaders.cubemap_filter.init(); + bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx"); + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::LOW_QUALITY, !ggx_hq); { // quad for copying stuff @@ -4201,13 +5989,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; @@ -4219,20 +6007,36 @@ 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); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); //need this for proper sampling glBindTexture(GL_TEXTURE_2D, 0); } + { + + glGenFramebuffers(1, &resources.mipmap_blur_fbo); + glGenTextures(1, &resources.mipmap_blur_color); + } + #ifdef GLES_OVER_GL - glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); + //this needs to be enabled manually in OpenGL 2.1 + + if (config.extensions.has("GL_ARB_seamless_cube_map")) { + 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"); + config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter"); } void RasterizerStorageGLES2::finalize() { @@ -4247,6 +6051,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 e6708914ec..2e78910614 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -31,7 +31,7 @@ #ifndef RASTERIZERSTORAGEGLES2_H #define RASTERIZERSTORAGEGLES2_H -#include "core/dvector.h" +#include "core/pool_vector.h" #include "core/self_list.h" #include "servers/visual/rasterizer.h" #include "servers/visual/shader_language.h" @@ -43,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" */ @@ -61,31 +60,46 @@ public: bool shrink_textures_x2; bool use_fast_texture_filter; - // bool use_anisotropic_filter; - - bool hdr_supported; - - bool use_rgba_2d_shadows; - - // float anisotropic_level; + bool use_skeleton_software; + int max_vertex_texture_image_units; int max_texture_image_units; int max_texture_size; - bool generate_wireframes; - - bool use_texture_array_environment; + // TODO implement wireframe in GLES2 + // bool generate_wireframes; Set<String> extensions; bool float_texture_supported; bool s3tc_supported; bool etc1_supported; + bool pvrtc_supported; + bool rgtc_supported; + bool bptc_supported; bool keep_original_textures; - bool no_depth_prepass; bool force_vertex_shading; + + bool use_rgba_2d_shadows; + bool use_rgba_3d_shadows; + + bool support_32_bits_indices; + bool support_write_depth; + bool support_half_float_vertices; + bool support_npot_repeat_mipmap; + bool support_depth_texture; + bool support_depth_cubemaps; + + bool support_shadow_cubemaps; + + bool multisample_supported; + bool render_to_mipmap_supported; + + GLuint depth_internalformat; + GLuint depth_type; + } config; struct Resources { @@ -95,7 +109,11 @@ public: GLuint normal_tex; GLuint aniso_tex; + GLuint mipmap_blur_fbo; + GLuint mipmap_blur_color; + GLuint radical_inverse_vdc_cache_tex; + bool use_rgba_2d_shadows; GLuint quadie; @@ -141,10 +159,9 @@ public: } } render, render_final, snap; - Info() { - - texture_mem = 0; - vertex_mem = 0; + Info() : + texture_mem(0), + vertex_mem(0) { render.reset(); render_final.reset(); } @@ -157,23 +174,15 @@ public: //////////////////////////////////DATA/////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// - struct Instanciable : public RID_Data { + struct Instantiable : public RID_Data { SelfList<RasterizerScene::InstanceBase>::List instance_list; - _FORCE_INLINE_ void instance_change_notify() { - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); + _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { - while (instances) { - instances->self()->base_changed(); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_material_change_notify() { SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - instances->self()->base_material_changed(); + + instances->self()->base_changed(p_aabb, p_materials); instances = instances->next(); } } @@ -187,15 +196,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, @@ -252,6 +261,8 @@ public: int mipmaps; + bool resize_to_po2; + bool active; GLenum tex_id; @@ -272,33 +283,33 @@ public: VisualServer::TextureDetectCallback detect_normal; void *detect_normal_ud; - Texture() { - flags = 0; - width = 0; - height = 0; - alloc_width = 0; - alloc_height = 0; - format = Image::FORMAT_L8; - - target = 0; - - data_size = 0; - total_data_size = 0; - ignore_mipmaps = false; - - compressed = false; - - active = false; - - tex_id = 0; - - stored_cube_sides = 0; - - proxy = NULL; - - render_target = NULL; - - redraw_if_visible = false; + Texture() : + proxy(NULL), + flags(0), + width(0), + height(0), + alloc_width(0), + alloc_height(0), + format(Image::FORMAT_L8), + type(VS::TEXTURE_TYPE_2D), + target(0), + data_size(0), + total_data_size(0), + ignore_mipmaps(false), + compressed(false), + mipmaps(0), + resize_to_po2(false), + active(false), + tex_id(0), + stored_cube_sides(0), + render_target(NULL), + redraw_if_visible(false), + detect_3d(NULL), + detect_3d_ud(NULL), + detect_srgb(NULL), + detect_srgb_ud(NULL), + detect_normal(NULL), + detect_normal_ud(NULL) { } _ALWAYS_INLINE_ Texture *get_ptr() { @@ -326,7 +337,7 @@ public: mutable RID_Owner<Texture> texture_owner; - Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const; + Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool p_will_need_resize) const; virtual RID texture_create(); virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT); @@ -342,6 +353,7 @@ public: virtual uint32_t texture_get_height(RID p_texture) const; virtual uint32_t texture_get_depth(RID p_texture) const; virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth); + virtual void texture_bind(RID p_texture, uint32_t p_texture_no); virtual void texture_set_path(RID p_texture, const String &p_path); virtual String texture_get_path(RID p_texture) const; @@ -355,6 +367,7 @@ public: virtual void textures_keep_original(bool p_enable); virtual void texture_set_proxy(RID p_texture, RID p_proxy); + virtual Size2 texture_size_with_proxy(RID p_texture) const; virtual void texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata); virtual void texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata); @@ -421,7 +434,6 @@ public: int blend_mode; - /* enum LightMode { LIGHT_MODE_NORMAL, LIGHT_MODE_UNSHADED, @@ -429,7 +441,7 @@ public: }; int light_mode; - */ + bool uses_screen_texture; bool uses_screen_uv; bool uses_time; @@ -632,23 +644,19 @@ public: PoolVector<uint8_t> data; PoolVector<uint8_t> index_data; + Vector<PoolVector<uint8_t> > blend_shape_data; int total_data_size; - Surface() { - array_byte_size = 0; - index_array_byte_size = 0; - - array_len = 0; - index_array_len = 0; - - mesh = NULL; - - primitive = VS::PRIMITIVE_POINTS; - - active = false; - - total_data_size = 0; + Surface() : + mesh(NULL), + array_len(0), + index_array_len(0), + array_byte_size(0), + index_array_byte_size(0), + primitive(VS::PRIMITIVE_POINTS), + active(false), + total_data_size(0) { } }; @@ -673,14 +681,14 @@ public: SelfList<MultiMesh> *mm = multimeshes.first(); while (mm) { - mm->self()->instance_material_change_notify(); + mm->self()->instance_change_notify(false, true); mm = mm->next(); } } - Mesh() { - blend_shape_mode = VS::BLEND_SHAPE_MODE_NORMALIZED; - blend_shape_count = 0; + Mesh() : + blend_shape_count(0), + blend_shape_mode(VS::BLEND_SHAPE_MODE_NORMALIZED) { } }; @@ -751,22 +759,18 @@ public: bool dirty_data; MultiMesh() : + size(0), + transform_format(VS::MULTIMESH_TRANSFORM_2D), + color_format(VS::MULTIMESH_COLOR_NONE), + custom_data_format(VS::MULTIMESH_CUSTOM_DATA_NONE), update_list(this), - mesh_list(this) { - dirty_aabb = true; - dirty_data = true; - - xform_floats = 0; - color_floats = 0; - custom_data_floats = 0; - - visible_instances = -1; - - size = 0; - - transform_format = VS::MULTIMESH_TRANSFORM_2D; - color_format = VS::MULTIMESH_COLOR_NONE; - custom_data_format = VS::MULTIMESH_CUSTOM_DATA_NONE; + mesh_list(this), + visible_instances(-1), + xform_floats(0), + color_floats(0), + custom_data_floats(0), + dirty_aabb(true), + dirty_data(true) { } }; @@ -866,11 +870,13 @@ public: SelfList<Skeleton> update_list; Set<RasterizerScene::InstanceBase *> instances; + Transform2D base_transform_2d; + Skeleton() : + use_2d(false), + size(0), + tex_id(0), update_list(this) { - tex_id = 0; - size = 0; - use_2d = false; } }; @@ -893,7 +899,7 @@ public: /* Light API */ - struct Light : Instanciable { + struct Light : Instantiable { VS::LightType type; float param[VS::LIGHT_PARAM_MAX]; @@ -905,6 +911,7 @@ public: bool shadow; bool negative; bool reverse_cull; + bool use_gi; uint32_t cull_mask; @@ -931,6 +938,7 @@ public: virtual void light_set_negative(RID p_light, bool p_enable); virtual void light_set_cull_mask(RID p_light, uint32_t p_mask); virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled); + virtual void light_set_use_gi(RID p_light, bool p_enabled); virtual void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode); virtual void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail); @@ -950,11 +958,32 @@ public: virtual VS::LightType light_get_type(RID p_light) const; virtual float light_get_param(RID p_light, VS::LightParam p_param); virtual Color light_get_color(RID p_light); + virtual bool light_get_use_gi(RID p_light); virtual AABB light_get_aabb(RID p_light) const; 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); @@ -969,11 +998,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; @@ -1023,6 +1055,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; @@ -1072,6 +1119,8 @@ public: virtual int particles_get_draw_passes(RID p_particles) const; virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const; + virtual bool particles_is_inactive(RID p_particles) const; + /* INSTANCE */ virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); @@ -1084,15 +1133,13 @@ public: struct RenderTarget : public RID_Data { GLuint fbo; - GLuint color; GLuint depth; - // TODO post processing effects? - - // TODO HDR? - - // TODO this is hardcoded for texscreen copies for now + GLuint multisample_fbo; + GLuint multisample_color; + GLuint multisample_depth; + bool multisample_active; struct Effect { GLuint fbo; @@ -1101,17 +1148,48 @@ public: GLuint color; - Effect() { - fbo = 0; - width = 0; - height = 0; - color = 0; + Effect() : + fbo(0), + width(0), + height(0), + color(0) { } }; Effect copy_screen_effect; - int width, height; + struct MipMaps { + + struct Size { + GLuint fbo; + GLuint color; + int width; + int height; + }; + + Vector<Size> sizes; + GLuint color; + int levels; + + MipMaps() : + color(0), + levels(0) { + } + }; + + MipMaps mip_maps[2]; + + struct External { + GLuint fbo; + GLuint color; + RID texture; + + External() : + fbo(0) { + } + } external; + + int x, y, width, height; bool flags[RENDER_TARGET_FLAG_MAX]; @@ -1120,22 +1198,29 @@ public: RID texture; - RenderTarget() { - fbo = 0; - - color = 0; - depth = 0; - - width = 0; - height = 0; - - for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { + bool used_dof_blur_near; + bool mip_maps_allocated; + + RenderTarget() : + fbo(0), + color(0), + depth(0), + multisample_fbo(0), + multisample_color(0), + multisample_depth(0), + multisample_active(false), + x(0), + y(0), + width(0), + height(0), + used_in_frame(false), + msaa(VS::VIEWPORT_MSAA_DISABLED), + used_dof_blur_near(false), + mip_maps_allocated(false) { + for (int i = 0; i < RENDER_TARGET_FLAG_MAX; ++i) { flags[i] = false; } - - used_in_frame = false; - - msaa = VS::VIEWPORT_MSAA_DISABLED; + external.fbo = 0; } }; @@ -1145,8 +1230,10 @@ public: void _render_target_allocate(RenderTarget *rt); virtual RID render_target_create(); + virtual void render_target_set_position(RID p_render_target, int p_x, int p_y); virtual void render_target_set_size(RID p_render_target, int p_width, int p_height); virtual RID render_target_get_texture(RID p_render_target) const; + virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id); virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); virtual bool render_target_was_used(RID p_render_target); @@ -1155,10 +1242,31 @@ public: /* CANVAS SHADOW */ + struct CanvasLightShadow : public RID_Data { + + int size; + int height; + GLuint fbo; + GLuint depth; + GLuint distance; //for older devices + }; + + RID_Owner<CanvasLightShadow> canvas_light_shadow_owner; + virtual RID canvas_light_shadow_buffer_create(int p_width); /* LIGHT SHADOW MAPPING */ + struct CanvasOccluder : public RID_Data { + + GLuint vertex_id; // 0 means, unconfigured + GLuint index_id; // 0 means, unconfigured + PoolVector<Vector2> lines; + int len; + }; + + RID_Owner<CanvasOccluder> canvas_occluder_owner; + virtual RID canvas_light_occluder_create(); virtual void canvas_light_occluder_set_polylines(RID p_occluder, const PoolVector<Vector2> &p_lines); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index bedcfbb798..1db8a870a2 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* shader_compiler_gles3.cpp */ +/* shader_compiler_gles2.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -80,19 +80,17 @@ static String _opstr(SL::Operator p_op) { static String _mkid(const String &p_id) { - StringBuffer<> id; - id += "m_"; - id += p_id; - - return id.as_string(); + String id = "m_" + p_id; + return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl } static String f2sp0(float p_float) { - if (int(p_float) == p_float) - return itos(p_float) + ".0"; - else - return rtoss(p_float); + String num = rtoss(p_float); + if (num.find(".") == -1 && num.find("e") == -1) { + num += ".0"; + } + return num; } static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { @@ -318,9 +316,14 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener for (Map<StringName, SL::ShaderNode::Uniform>::Element *E = snode->uniforms.front(); E; E = E->next()) { StringBuffer<> uniform_code; - uniform_code += "uniform "; + // use highp if no precision is specified to prevent different default values in fragment and vertex shader + SL::DataPrecision precision = E->get().precision; + if (precision == SL::PRECISION_DEFAULT && E->get().type != SL::TYPE_BOOL) { + precision = SL::PRECISION_HIGHP; + } - uniform_code += _prestr(E->get().precission); + uniform_code += "uniform "; + uniform_code += _prestr(precision); uniform_code += _typestr(E->get().type); uniform_code += " "; uniform_code += _mkid(E->key()); @@ -346,10 +349,15 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener StringBuffer<> varying_code; varying_code += "varying "; - varying_code += _prestr(E->get().precission); + varying_code += _prestr(E->get().precision); varying_code += _typestr(E->get().type); varying_code += " "; varying_code += _mkid(E->key()); + if (E->get().array_size > 0) { + varying_code += "["; + varying_code += itos(E->get().array_size); + varying_code += "]"; + } varying_code += ";\n"; String final_code = varying_code.as_string(); @@ -358,12 +366,28 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener fragment_global += final_code; } + // constants + + for (Map<StringName, SL::ShaderNode::Constant>::Element *E = snode->constants.front(); E; E = E->next()) { + String gcode; + gcode += "const "; + gcode += _prestr(E->get().precision); + gcode += _typestr(E->get().type); + gcode += " " + _mkid(E->key()); + gcode += "="; + gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + gcode += ";\n"; + vertex_global += gcode; + fragment_global += gcode; + } + // functions Map<StringName, String> function_code; for (int i = 0; i < snode->functions.size(); i++) { SL::FunctionNode *fnode = snode->functions[i].function; + current_func_name = fnode->name; function_code[fnode->name] = _dump_node_code(fnode->body, 1, r_gen_code, p_actions, p_default_actions, p_assigning); } @@ -430,7 +454,9 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener SL::VariableDeclarationNode *var_dec_node = (SL::VariableDeclarationNode *)p_node; StringBuffer<> declaration; - + if (var_dec_node->is_const) { + declaration += "const "; + } declaration += _prestr(var_dec_node->precision); declaration += _typestr(var_dec_node->datatype); @@ -491,7 +517,99 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener } } } break; + case SL::Node::TYPE_ARRAY_DECLARATION: { + SL::ArrayDeclarationNode *arr_dec_node = (SL::ArrayDeclarationNode *)p_node; + + StringBuffer<> declaration; + if (arr_dec_node->is_const) { + declaration += "const "; + } + declaration += _prestr(arr_dec_node->precision); + declaration += _typestr(arr_dec_node->datatype); + + for (int i = 0; i < arr_dec_node->declarations.size(); i++) { + + if (i > 0) { + declaration += ","; + } + + declaration += " "; + + declaration += _mkid(arr_dec_node->declarations[i].name); + declaration += "["; + declaration += itos(arr_dec_node->declarations[i].size); + declaration += "]"; + int sz = arr_dec_node->declarations[i].initializer.size(); + if (sz > 0) { + declaration += "="; + declaration += _typestr(arr_dec_node->datatype); + declaration += "["; + declaration += itos(sz); + declaration += "]"; + declaration += "("; + for (int j = 0; j < sz; j++) { + declaration += _dump_node_code(arr_dec_node->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + if (j != sz - 1) { + declaration += ", "; + } + } + declaration += ")"; + } + } + + code += declaration.as_string(); + } break; + case SL::Node::TYPE_ARRAY: { + SL::ArrayNode *arr_node = (SL::ArrayNode *)p_node; + + if (p_assigning && p_actions.write_flag_pointers.has(arr_node->name)) { + *p_actions.write_flag_pointers[arr_node->name] = true; + } + + if (p_default_actions.usage_defines.has(arr_node->name) && !used_name_defines.has(arr_node->name)) { + String define = p_default_actions.usage_defines[arr_node->name]; + + if (define.begins_with("@")) { + define = p_default_actions.usage_defines[define.substr(1, define.length())]; + } + + r_gen_code.custom_defines.push_back(define.utf8()); + used_name_defines.insert(arr_node->name); + } + + if (p_actions.usage_flag_pointers.has(arr_node->name) && !used_flag_pointers.has(arr_node->name)) { + *p_actions.usage_flag_pointers[arr_node->name] = true; + used_flag_pointers.insert(arr_node->name); + } + + if (p_default_actions.renames.has(arr_node->name)) { + code += p_default_actions.renames[arr_node->name]; + } else { + code += _mkid(arr_node->name); + } + + if (arr_node->call_expression != NULL) { + code += "."; + code += _dump_node_code(arr_node->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } + + if (arr_node->index_expression != NULL) { + code += "["; + code += _dump_node_code(arr_node->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += "]"; + } + + if (arr_node->name == time_name) { + if (current_func_name == vertex_name) { + r_gen_code.uses_vertex_time = true; + } + if (current_func_name == fragment_name || current_func_name == light_name) { + r_gen_code.uses_fragment_time = true; + } + } + + } break; case SL::Node::TYPE_CONSTANT: { SL::ConstantNode *const_node = (SL::ConstantNode *)p_node; @@ -624,6 +742,17 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += ")"; + if (p_default_actions.usage_defines.has(var_node->name) && !used_name_defines.has(var_node->name)) { + String define = p_default_actions.usage_defines[var_node->name]; + + if (define.begins_with("@")) { + define = p_default_actions.usage_defines[define.substr(1, define.length())]; + } + + r_gen_code.custom_defines.push_back(define.utf8()); + used_name_defines.insert(var_node->name); + } + } break; case SL::OP_INDEX: { @@ -634,20 +763,22 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::OP_SELECT_IF: { + code += "("; code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += " ? "; code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += " : "; code += _dump_node_code(op_node->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ")"; } break; 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: { @@ -678,6 +809,23 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener code += "else\n"; code += _dump_node_code(cf_node->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } + } else if (cf_node->flow_op == SL::FLOW_OP_SWITCH) { + code += _mktab(p_level) + "switch (" + _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cf_node->flow_op == SL::FLOW_OP_CASE) { + code += _mktab(p_level) + "case " + _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ":\n"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cf_node->flow_op == SL::FLOW_OP_DEFAULT) { + code += _mktab(p_level) + "default:\n"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cf_node->flow_op == SL::FLOW_OP_DO) { + code += _mktab(p_level); + code += "do"; + code += _dump_node_code(cf_node->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _mktab(p_level); + code += "while ("; + code += _dump_node_code(cf_node->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ");"; } else if (cf_node->flow_op == SL::FLOW_OP_WHILE) { code += _mktab(p_level); code += "while ("; @@ -738,7 +886,7 @@ Error ShaderCompilerGLES2::compile(VS::ShaderMode p_mode, const String &p_code, Vector<String> shader = p_code.split("\n"); for (int i = 0; i < shader.size(); i++) { - print_line(itos(i) + " " + shader[i]); + print_line(itos(i + 1) + " " + shader[i]); } _err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER); @@ -771,12 +919,12 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { /** CANVAS ITEM SHADER **/ actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy"; - actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp"; + actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv"; actions[VS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "gl_PointSize"; actions[VS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix"; actions[VS::SHADER_CANVAS_ITEM].renames["PROJECTION_MATRIX"] = "projection_matrix"; - actions[VS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] = "extra_matrix"; + actions[VS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] = "extra_matrix_instance"; actions[VS::SHADER_CANVAS_ITEM].renames["TIME"] = "time"; actions[VS::SHADER_CANVAS_ITEM].renames["AT_LIGHT_PASS"] = "at_light_pass"; actions[VS::SHADER_CANVAS_ITEM].renames["INSTANCE_CUSTOM"] = "instance_custom"; @@ -800,6 +948,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv"; actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light"; actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color"; + actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_VEC"] = "shadow_vec"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; @@ -807,16 +956,33 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; - actions[VS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_COLOR"] = "#define SHADOW_COLOR_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; - actions[VS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_VEC"] = "#define SHADOW_VEC_USED\n"; + + // Ported from GLES3 + + actions[VS::SHADER_CANVAS_ITEM].usage_defines["sinh"] = "#define SINH_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["cosh"] = "#define COSH_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["tanh"] = "#define TANH_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["asinh"] = "#define ASINH_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["acosh"] = "#define ACOSH_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["atanh"] = "#define ATANH_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["determinant"] = "#define DETERMINANT_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["transpose"] = "#define TRANSPOSE_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["round"] = "#define ROUND_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["inverse"] = "#define INVERSE_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["isinf"] = "#define IS_INF_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["isnan"] = "#define IS_NAN_USED\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["trunc"] = "#define TRUNC_USED\n"; /** SPATIAL SHADER **/ actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform"; - actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_matrix"; - actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_inverse_matrix"; + actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix"; + actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix"; actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix"; actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "projection_inverse_matrix"; actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; @@ -825,13 +991,13 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal"; actions[VS::SHADER_SPATIAL].renames["TANGENT"] = "tangent"; actions[VS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal"; + actions[VS::SHADER_SPATIAL].renames["POSITION"] = "position"; actions[VS::SHADER_SPATIAL].renames["UV"] = "uv_interp"; actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; 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 @@ -862,13 +1028,16 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom"; 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["SIDE"] = "side"; + actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_texture"; + // Defined in GLES3, but not available in GLES2 + //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"; actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; + actions[VS::SHADER_SPATIAL].renames["LIGHT"] = "light"; actions[VS::SHADER_SPATIAL].renames["ATTENUATION"] = "attenuation"; actions[VS::SHADER_SPATIAL].renames["DIFFUSE_LIGHT"] = "diffuse_light"; actions[VS::SHADER_SPATIAL].renames["SPECULAR_LIGHT"] = "specular_light"; @@ -890,18 +1059,44 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; actions[VS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["DEPTH_TEXTURE"] = "#define DEPTH_TEXTURE_USED\n"; actions[VS::SHADER_SPATIAL].usage_defines["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + // Ported from GLES3 + + actions[VS::SHADER_SPATIAL].usage_defines["sinh"] = "#define SINH_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["cosh"] = "#define COSH_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["tanh"] = "#define TANH_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["asinh"] = "#define ASINH_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["acosh"] = "#define ACOSH_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["atanh"] = "#define ATANH_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["determinant"] = "#define DETERMINANT_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["transpose"] = "#define TRANSPOSE_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["outerProduct"] = "#define OUTER_PRODUCT_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["round"] = "#define ROUND_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["roundEven"] = "#define ROUND_EVEN_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["inverse"] = "#define INVERSE_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["isinf"] = "#define IS_INF_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["isnan"] = "#define IS_NAN_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["trunc"] = "#define TRUNC_USED\n"; + 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"; + // Defined in GLES3, could be implemented in GLES2 too if there's a need for it + //actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n"; + // Defined in GLES3, might not be possible in GLES2 as gl_FrontFacing is not available + //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"; + bool force_lambert = GLOBAL_GET("rendering/quality/shading/force_lambert_over_burley"); if (!force_lambert) { @@ -926,28 +1121,9 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { 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"; + actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; - /* PARTICLES SHADER */ - - actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color"; - actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz"; - actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass"; - actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "active"; - actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart"; - actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom"; - actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform"; - actions[VS::SHADER_PARTICLES].renames["TIME"] = "time"; - actions[VS::SHADER_PARTICLES].renames["LIFETIME"] = "lifetime"; - actions[VS::SHADER_PARTICLES].renames["DELTA"] = "local_delta"; - actions[VS::SHADER_PARTICLES].renames["NUMBER"] = "particle_number"; - actions[VS::SHADER_PARTICLES].renames["INDEX"] = "index"; - actions[VS::SHADER_PARTICLES].renames["GRAVITY"] = "current_gravity"; - actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform"; - actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed"; - - actions[VS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; - actions[VS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; - actions[VS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; + // No defines for particle shaders in GLES2, there are no GPU particles vertex_name = "vertex"; fragment_name = "fragment"; diff --git a/drivers/gles2/shader_compiler_gles2.h b/drivers/gles2/shader_compiler_gles2.h index 5e9e295204..b8f50d6d1f 100644 --- a/drivers/gles2/shader_compiler_gles2.h +++ b/drivers/gles2/shader_compiler_gles2.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index 650e8f7c42..58eff791ca 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -69,51 +69,6 @@ ShaderGLES2 *ShaderGLES2::active = NULL; #endif -void ShaderGLES2::bind_uniforms() { - if (!uniforms_dirty) - return; - - // regular uniforms - - const Map<uint32_t, Variant>::Element *E = uniform_defaults.front(); - - while (E) { - int idx = E->key(); - int location = version->uniform_location[idx]; - - if (location < 0) { - E = E->next(); - continue; - } - - Variant v; - - v = E->value(); - - _set_uniform_variant(location, v); - E = E->next(); - } - - // camera uniforms - - const Map<uint32_t, CameraMatrix>::Element *C = uniform_cameras.front(); - - while (C) { - int idx = E->key(); - int location = version->uniform_location[idx]; - - if (location < 0) { - C = C->next(); - continue; - } - - glUniformMatrix4fv(location, 1, GL_FALSE, &(C->get().matrix[0][0])); - C = C->next(); - } - - uniforms_dirty = false; -} - GLint ShaderGLES2::get_uniform_location(int p_index) const { ERR_FAIL_COND_V(!version, -1); @@ -139,28 +94,6 @@ bool ShaderGLES2::bind() { glUseProgram(version->id); - // find out uniform names and locations - - int count; - glGetProgramiv(version->id, GL_ACTIVE_UNIFORMS, &count); - version->uniform_names.resize(count); - - for (int i = 0; i < count; i++) { - GLchar uniform_name[1024]; - int len = 0; - GLint size = 0; - GLenum type; - - glGetActiveUniform(version->id, i, 1024, &len, &size, &type, uniform_name); - - uniform_name[len] = '\0'; - String name = String((const char *)uniform_name); - - version->uniform_names.write[i] = name; - } - - bind_uniforms(); - DEBUG_TEST_ERROR("use program"); active = this; @@ -196,6 +129,12 @@ static void _display_error_with_code(const String &p_error, const Vector<const c ERR_PRINTS(p_error); } +static String _mkid(const String &p_id) { + + String id = "m_" + p_id; + return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl +} + ShaderGLES2::Version *ShaderGLES2::get_current_version() { Version *_v = version_map.getptr(conditional_version); @@ -236,16 +175,18 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { strings.push_back("#define USE_GLES_OVER_GL\n"); #else strings.push_back("#version 100\n"); +//angle does not like +#ifdef JAVASCRIPT_ENABLED + strings.push_back("#define USE_HIGHP_PRECISION\n"); #endif - int define_line_ofs = 1; +#endif for (int j = 0; j < conditional_count; j++) { bool enable = (conditional_version.version & (1 << j)) > 0; if (enable) { strings.push_back(conditional_defines[j]); - define_line_ofs++; DEBUG_PRINT(conditional_defines[j]); } } @@ -262,7 +203,6 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { ERR_FAIL_COND_V(!cc, NULL); v.code_version = cc->version; - define_line_ofs += 2; } // program @@ -358,14 +298,14 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { strings.push_back(fragment_code1.get_data()); if (cc) { - code_string = cc->fragment.ascii(); + code_string = cc->light.ascii(); strings.push_back(code_string.get_data()); } strings.push_back(fragment_code2.get_data()); if (cc) { - code_string2 = cc->light.ascii(); + code_string2 = cc->fragment.ascii(); strings.push_back(code_string2.get_data()); } @@ -492,22 +432,27 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { if (cc) { // uniforms for (int i = 0; i < cc->custom_uniforms.size(); i++) { - StringName native_uniform_name = "m_" + cc->custom_uniforms[i]; - GLint location = glGetUniformLocation(v.id, ((String)native_uniform_name).ascii().get_data()); + String native_uniform_name = _mkid(cc->custom_uniforms[i]); + GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); v.custom_uniform_locations[cc->custom_uniforms[i]] = location; } // textures for (int i = 0; i < cc->texture_uniforms.size(); i++) { - StringName native_uniform_name = "m_" + cc->texture_uniforms[i]; - GLint location = glGetUniformLocation(v.id, ((String)native_uniform_name).ascii().get_data()); + String native_uniform_name = _mkid(cc->texture_uniforms[i]); + GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); v.custom_uniform_locations[cc->texture_uniforms[i]] = location; + glUniform1i(location, i); } } glUseProgram(0); v.ok = true; + if (cc) { + cc->versions.insert(conditional_version.version); + } + return &v; } @@ -582,22 +527,24 @@ void ShaderGLES2::setup( fragment_code0 = code.substr(0, cpos).ascii(); code = code.substr(cpos + globals_tag.length(), code.length()); - cpos = code.find(code_tag); + cpos = code.find(light_code_tag); - if (cpos == -1) { - fragment_code1 = code.ascii(); - } else { + String code2; + + if (cpos != -1) { fragment_code1 = code.substr(0, cpos).ascii(); - String code2 = code.substr(cpos + code_tag.length(), code.length()); - - cpos = code2.find(light_code_tag); - if (cpos == -1) { - fragment_code2 = code2.ascii(); - } else { - fragment_code2 = code2.substr(0, cpos).ascii(); - fragment_code3 = code2.substr(cpos + light_code_tag.length(), code2.length()).ascii(); - } + code2 = code.substr(cpos + light_code_tag.length(), code.length()); + } else { + code2 = code; + } + + cpos = code2.find(code_tag); + if (cpos == -1) { + fragment_code2 = code2.ascii(); + } else { + fragment_code2 = code2.substr(0, cpos).ascii(); + fragment_code3 = code2.substr(cpos + code_tag.length(), code2.length()).ascii(); } } } @@ -670,9 +617,28 @@ void ShaderGLES2::set_custom_shader(uint32_t p_code_id) { } void ShaderGLES2::free_custom_shader(uint32_t p_code_id) { + ERR_FAIL_COND(!custom_code_map.has(p_code_id)); - if (conditional_version.code_version == p_code_id) - conditional_version.code_version = 0; + if (conditional_version.code_version == p_code_id) { + conditional_version.code_version = 0; //do not keep using a version that is going away + unbind(); + } + + VersionKey key; + key.code_version = p_code_id; + for (Set<uint32_t>::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) { + key.version = E->get(); + ERR_CONTINUE(!version_map.has(key)); + Version &v = version_map[key]; + + glDeleteShader(v.vert_id); + glDeleteShader(v.frag_id); + glDeleteProgram(v.id); + memdelete_arr(v.uniform_location); + v.id = 0; + + version_map.erase(key); + } custom_code_map.erase(p_code_id); } @@ -690,355 +656,440 @@ 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()) { if (E->get().texture_order >= 0) continue; // this is a texture, doesn't go here - Map<StringName, Variant>::Element *V = material->params.find(E->key()); + Map<StringName, GLint>::Element *L = v->custom_uniform_locations.find(E->key()); + if (!L || L->get() < 0) + continue; //uniform not valid - Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > value; + GLuint location = L->get(); - value.first = E->get().type; - value.second = E->get().default_value; + Map<StringName, Variant>::Element *V = material->params.find(E->key()); if (V) { - value.second = Vector<ShaderLanguage::ConstantNode::Value>(); - value.second.resize(E->get().default_value.size()); switch (E->get().type) { case ShaderLanguage::TYPE_BOOL: { - if (value.second.size() < 1) - value.second.resize(1); - value.second.write[0].boolean = V->get(); + + bool boolean = V->get(); + glUniform1i(location, boolean ? 1 : 0); } break; case ShaderLanguage::TYPE_BVEC2: { - if (value.second.size() < 2) - value.second.resize(2); int flags = V->get(); - value.second.write[0].boolean = flags & 1; - value.second.write[1].boolean = flags & 2; + glUniform2i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0); } break; case ShaderLanguage::TYPE_BVEC3: { - if (value.second.size() < 3) - value.second.resize(3); + int flags = V->get(); - value.second.write[0].boolean = flags & 1; - value.second.write[1].boolean = flags & 2; - value.second.write[2].boolean = flags & 4; + glUniform3i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0); } break; case ShaderLanguage::TYPE_BVEC4: { - if (value.second.size() < 4) - value.second.resize(4); int flags = V->get(); - value.second.write[0].boolean = flags & 1; - value.second.write[1].boolean = flags & 2; - value.second.write[2].boolean = flags & 4; - value.second.write[3].boolean = flags & 8; + glUniform4i(location, (flags & 1) ? 1 : 0, (flags & 2) ? 1 : 0, (flags & 4) ? 1 : 0, (flags & 8) ? 1 : 0); } break; - case ShaderLanguage::TYPE_INT: { - if (value.second.size() < 1) - value.second.resize(1); - int val = V->get(); - value.second.write[0].sint = val; + case ShaderLanguage::TYPE_INT: + case ShaderLanguage::TYPE_UINT: { + int value = V->get(); + glUniform1i(location, value); } break; - case ShaderLanguage::TYPE_IVEC2: { - if (value.second.size() < 2) - value.second.resize(2); - PoolIntArray val = V->get(); - for (int i = 0; i < val.size(); i++) { - value.second.write[i].sint = val[i]; + case ShaderLanguage::TYPE_IVEC2: + case ShaderLanguage::TYPE_UVEC2: { + + Array r = V->get(); + const int count = 2; + if (r.size() == count) { + int values[count]; + for (int i = 0; i < count; i++) { + values[i] = r[i]; + } + glUniform2i(location, values[0], values[1]); } + } break; - case ShaderLanguage::TYPE_IVEC3: { - if (value.second.size() < 3) - value.second.resize(3); - PoolIntArray val = V->get(); - for (int i = 0; i < val.size(); i++) { - value.second.write[i].sint = val[i]; + case ShaderLanguage::TYPE_IVEC3: + case ShaderLanguage::TYPE_UVEC3: { + Array r = V->get(); + const int count = 3; + if (r.size() == count) { + int values[count]; + for (int i = 0; i < count; i++) { + values[i] = r[i]; + } + glUniform3i(location, values[0], values[1], values[2]); } } break; - case ShaderLanguage::TYPE_IVEC4: { - if (value.second.size() < 4) - value.second.resize(4); - PoolIntArray val = V->get(); - for (int i = 0; i < val.size(); i++) { - value.second.write[i].sint = val[i]; + case ShaderLanguage::TYPE_IVEC4: + case ShaderLanguage::TYPE_UVEC4: { + Array r = V->get(); + const int count = 4; + if (r.size() == count) { + int values[count]; + for (int i = 0; i < count; i++) { + values[i] = r[i]; + } + glUniform4i(location, values[0], values[1], values[2], values[3]); } } break; - case ShaderLanguage::TYPE_UINT: { - if (value.second.size() < 1) - value.second.resize(1); - uint32_t val = V->get(); - value.second.write[0].uint = val; + case ShaderLanguage::TYPE_FLOAT: { + float value = V->get(); + glUniform1f(location, value); + } break; - case ShaderLanguage::TYPE_UVEC2: { - if (value.second.size() < 2) - value.second.resize(2); - PoolIntArray val = V->get(); - for (int i = 0; i < val.size(); i++) { - value.second.write[i].uint = val[i]; - } + case ShaderLanguage::TYPE_VEC2: { + Vector2 value = V->get(); + glUniform2f(location, value.x, value.y); + } break; + case ShaderLanguage::TYPE_VEC3: { + Vector3 value = V->get(); + glUniform3f(location, value.x, value.y, value.z); } break; - case ShaderLanguage::TYPE_UVEC3: { - if (value.second.size() < 3) - value.second.resize(3); - PoolIntArray val = V->get(); - for (int i = 0; i < val.size(); i++) { - value.second.write[i].uint = val[i]; + case ShaderLanguage::TYPE_VEC4: { + if (V->get().get_type() == Variant::COLOR) { + Color value = V->get(); + glUniform4f(location, value.r, value.g, value.b, value.a); + } else if (V->get().get_type() == Variant::QUAT) { + Quat value = V->get(); + glUniform4f(location, value.x, value.y, value.z, value.w); + } else { + Plane value = V->get(); + glUniform4f(location, value.normal.x, value.normal.y, value.normal.z, value.d); } } break; - case ShaderLanguage::TYPE_UVEC4: { - if (value.second.size() < 4) - value.second.resize(4); - PoolIntArray val = V->get(); - for (int i = 0; i < val.size(); i++) { - value.second.write[i].uint = val[i]; - } + case ShaderLanguage::TYPE_MAT2: { + + Transform2D tr = V->get(); + GLfloat matrix[4] = { + /* build a 16x16 matrix */ + tr.elements[0][0], + tr.elements[0][1], + tr.elements[1][0], + tr.elements[1][1], + }; + glUniformMatrix2fv(location, 1, GL_FALSE, matrix); } break; - case ShaderLanguage::TYPE_FLOAT: { - if (value.second.size() < 1) - value.second.resize(1); - value.second.write[0].real = V->get(); + case ShaderLanguage::TYPE_MAT3: { + Basis val = V->get(); + + GLfloat mat[9] = { + val.elements[0][0], + val.elements[1][0], + val.elements[2][0], + val.elements[0][1], + val.elements[1][1], + val.elements[2][1], + val.elements[0][2], + val.elements[1][2], + val.elements[2][2], + }; + + glUniformMatrix3fv(location, 1, GL_FALSE, mat); + + } break; + + case ShaderLanguage::TYPE_MAT4: { + + Transform2D tr = V->get(); + GLfloat matrix[16] = { /* build a 16x16 matrix */ + tr.elements[0][0], + tr.elements[0][1], + 0, + 0, + tr.elements[1][0], + tr.elements[1][1], + 0, + 0, + 0, + 0, + 1, + 0, + tr.elements[2][0], + tr.elements[2][1], + 0, + 1 + }; + + glUniformMatrix4fv(location, 1, GL_FALSE, matrix); + + } break; + + default: { + ERR_PRINT("ShaderNode type missing, bug?"); + } break; + } + } else if (E->get().default_value.size()) { + const Vector<ShaderLanguage::ConstantNode::Value> &values = E->get().default_value; + switch (E->get().type) { + case ShaderLanguage::TYPE_BOOL: { + glUniform1i(location, values[0].boolean); + } break; + + case ShaderLanguage::TYPE_BVEC2: { + glUniform2i(location, values[0].boolean, values[1].boolean); + } break; + + case ShaderLanguage::TYPE_BVEC3: { + glUniform3i(location, values[0].boolean, values[1].boolean, values[2].boolean); + } break; + + case ShaderLanguage::TYPE_BVEC4: { + glUniform4i(location, values[0].boolean, values[1].boolean, values[2].boolean, values[3].boolean); + } break; + + case ShaderLanguage::TYPE_INT: { + glUniform1i(location, values[0].sint); + } break; + + case ShaderLanguage::TYPE_IVEC2: { + glUniform2i(location, values[0].sint, values[1].sint); + } break; + + case ShaderLanguage::TYPE_IVEC3: { + glUniform3i(location, values[0].sint, values[1].sint, values[2].sint); + } break; + + case ShaderLanguage::TYPE_IVEC4: { + glUniform4i(location, values[0].sint, values[1].sint, values[2].sint, values[3].sint); + } break; + + case ShaderLanguage::TYPE_UINT: { + glUniform1i(location, values[0].uint); + } break; + + case ShaderLanguage::TYPE_UVEC2: { + glUniform2i(location, values[0].uint, values[1].uint); + } break; + case ShaderLanguage::TYPE_UVEC3: { + glUniform3i(location, values[0].uint, values[1].uint, values[2].uint); + } break; + + case ShaderLanguage::TYPE_UVEC4: { + glUniform4i(location, values[0].uint, values[1].uint, values[2].uint, values[3].uint); + } break; + + case ShaderLanguage::TYPE_FLOAT: { + glUniform1f(location, values[0].real); } break; case ShaderLanguage::TYPE_VEC2: { - if (value.second.size() < 2) - value.second.resize(2); - Vector2 val = V->get(); - value.second.write[0].real = val.x; - value.second.write[1].real = val.y; + glUniform2f(location, values[0].real, values[1].real); } break; case ShaderLanguage::TYPE_VEC3: { - if (value.second.size() < 3) - value.second.resize(3); - Vector3 val = V->get(); - value.second.write[0].real = val.x; - value.second.write[1].real = val.y; - value.second.write[2].real = val.z; + glUniform3f(location, values[0].real, values[1].real, values[2].real); } break; case ShaderLanguage::TYPE_VEC4: { - if (value.second.size() < 4) - value.second.resize(4); - if (V->get().get_type() == Variant::PLANE) { - Plane val = V->get(); - value.second.write[0].real = val.normal.x; - value.second.write[1].real = val.normal.y; - value.second.write[2].real = val.normal.z; - value.second.write[3].real = val.d; - } else { - Color val = V->get(); - value.second.write[0].real = val.r; - value.second.write[1].real = val.g; - value.second.write[2].real = val.b; - value.second.write[3].real = val.a; - } - + glUniform4f(location, values[0].real, values[1].real, values[2].real, values[3].real); } break; case ShaderLanguage::TYPE_MAT2: { - Transform2D val = V->get(); + GLfloat mat[4]; - if (value.second.size() < 4) { - value.second.resize(4); + for (int i = 0; i < 4; i++) { + mat[i] = values[i].real; } - value.second.write[0].real = val.elements[0][0]; - value.second.write[1].real = val.elements[0][1]; - value.second.write[2].real = val.elements[1][0]; - value.second.write[3].real = val.elements[1][1]; - + glUniformMatrix2fv(location, 1, GL_FALSE, mat); } break; case ShaderLanguage::TYPE_MAT3: { - Basis val = V->get(); + GLfloat mat[9]; - if (value.second.size() < 9) { - value.second.resize(9); + for (int i = 0; i < 9; i++) { + mat[i] = values[i].real; } - value.second.write[0].real = val.elements[0][0]; - value.second.write[1].real = val.elements[0][1]; - value.second.write[2].real = val.elements[0][2]; - value.second.write[3].real = val.elements[1][0]; - value.second.write[4].real = val.elements[1][1]; - value.second.write[5].real = val.elements[1][2]; - value.second.write[6].real = val.elements[2][0]; - value.second.write[7].real = val.elements[2][1]; - value.second.write[8].real = val.elements[2][2]; + glUniformMatrix3fv(location, 1, GL_FALSE, mat); + } break; case ShaderLanguage::TYPE_MAT4: { - Transform val = V->get(); + GLfloat mat[16]; - if (value.second.size() < 16) { - value.second.resize(16); + for (int i = 0; i < 16; i++) { + mat[i] = values[i].real; } - value.second.write[0].real = val.basis.elements[0][0]; - value.second.write[1].real = val.basis.elements[0][1]; - value.second.write[2].real = val.basis.elements[0][2]; - value.second.write[3].real = 0; - value.second.write[4].real = val.basis.elements[1][0]; - value.second.write[5].real = val.basis.elements[1][1]; - value.second.write[6].real = val.basis.elements[1][2]; - value.second.write[7].real = 0; - value.second.write[8].real = val.basis.elements[2][0]; - value.second.write[9].real = val.basis.elements[2][1]; - value.second.write[10].real = val.basis.elements[2][2]; - value.second.write[11].real = 0; - value.second.write[12].real = val.origin[0]; - value.second.write[13].real = val.origin[1]; - value.second.write[14].real = val.origin[2]; - value.second.write[15].real = 1; + glUniformMatrix4fv(location, 1, GL_FALSE, mat); + } break; - default: { + case ShaderLanguage::TYPE_SAMPLER2D: { } break; - } - } else { - if (value.second.size() == 0) { - // No default value set... weird, let's just use zero for everything - size_t default_arg_size = 1; - bool is_float = false; - switch (E->get().type) { - case ShaderLanguage::TYPE_BOOL: - case ShaderLanguage::TYPE_INT: - case ShaderLanguage::TYPE_UINT: { - default_arg_size = 1; - } break; - - case ShaderLanguage::TYPE_FLOAT: { - default_arg_size = 1; - is_float = true; - } break; - - case ShaderLanguage::TYPE_BVEC2: - case ShaderLanguage::TYPE_IVEC2: - case ShaderLanguage::TYPE_UVEC2: { - default_arg_size = 2; - } break; - - case ShaderLanguage::TYPE_VEC2: { - default_arg_size = 2; - is_float = true; - } break; - - case ShaderLanguage::TYPE_BVEC3: - case ShaderLanguage::TYPE_IVEC3: - case ShaderLanguage::TYPE_UVEC3: { - default_arg_size = 3; - } break; - - case ShaderLanguage::TYPE_VEC3: { - default_arg_size = 3; - is_float = true; - } break; - - case ShaderLanguage::TYPE_BVEC4: - case ShaderLanguage::TYPE_IVEC4: - case ShaderLanguage::TYPE_UVEC4: { - default_arg_size = 4; - } break; - - case ShaderLanguage::TYPE_VEC4: { - default_arg_size = 4; - is_float = true; - } break; - - default: { - // TODO matricies and all that stuff - default_arg_size = 1; - } break; - } - - value.second.resize(default_arg_size); - - for (int i = 0; i < default_arg_size; i++) { - if (is_float) { - value.second.write[i].real = 0.0; - } else { - value.second.write[i].uint = 0; - } - } - } - } - // GLint location = get_uniform_location(E->key()); + case ShaderLanguage::TYPE_ISAMPLER2D: { - GLint location; - if (v->custom_uniform_locations.has(E->key())) { - location = v->custom_uniform_locations[E->key()]; - } else { - int idx = v->uniform_names.find(E->key()); // TODO maybe put those in a Map? - if (idx < 0) { - location = -1; - } else { - location = v->uniform_location[idx]; + } break; + + case ShaderLanguage::TYPE_USAMPLER2D: { + + } break; + + 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; + default: { + ERR_PRINT("ShaderNode type missing, bug?"); + } break; } - } + } else { //zero - _set_uniform_value(location, value); - } + switch (E->get().type) { + case ShaderLanguage::TYPE_BOOL: { + glUniform1i(location, GL_FALSE); + } break; - // bind textures - int tc = material->textures.size(); - Pair<StringName, RID> *textures = material->textures.ptrw(); + case ShaderLanguage::TYPE_BVEC2: { + glUniform2i(location, GL_FALSE, GL_FALSE); + } break; - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = material->shader->texture_hints.ptrw(); + case ShaderLanguage::TYPE_BVEC3: { + glUniform3i(location, GL_FALSE, GL_FALSE, GL_FALSE); + } break; - for (int i = 0; i < tc; i++) { + case ShaderLanguage::TYPE_BVEC4: { + glUniform4i(location, GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); + } break; - Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > value; - value.first = ShaderLanguage::TYPE_INT; - value.second.resize(1); - value.second.write[0].sint = i; + case ShaderLanguage::TYPE_INT: { + glUniform1i(location, 0); + } break; - // GLint location = get_uniform_location(textures[i].first); + case ShaderLanguage::TYPE_IVEC2: { + glUniform2i(location, 0, 0); + } break; - // if (location < 0) { - // location = material->shader->uniform_locations[textures[i].first]; - // } - GLint location = -1; - if (v->custom_uniform_locations.has(textures[i].first)) { - location = v->custom_uniform_locations[textures[i].first]; - } else { - location = get_uniform_location(textures[i].first); - } + case ShaderLanguage::TYPE_IVEC3: { + glUniform3i(location, 0, 0, 0); + } break; - _set_uniform_value(location, value); - } -} + case ShaderLanguage::TYPE_IVEC4: { + glUniform4i(location, 0, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_UINT: { + glUniform1i(location, 0); + } break; + + case ShaderLanguage::TYPE_UVEC2: { + glUniform2i(location, 0, 0); + } break; + + case ShaderLanguage::TYPE_UVEC3: { + glUniform3i(location, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_UVEC4: { + glUniform4i(location, 0, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_FLOAT: { + glUniform1f(location, 0); + } break; + + case ShaderLanguage::TYPE_VEC2: { + glUniform2f(location, 0, 0); + } break; + + case ShaderLanguage::TYPE_VEC3: { + glUniform3f(location, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_VEC4: { + glUniform4f(location, 0, 0, 0, 0); + } break; + + case ShaderLanguage::TYPE_MAT2: { + GLfloat mat[4] = { 0, 0, 0, 0 }; + + glUniformMatrix2fv(location, 1, GL_FALSE, mat); + } break; + + case ShaderLanguage::TYPE_MAT3: { + GLfloat mat[9] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + + glUniformMatrix3fv(location, 1, GL_FALSE, mat); + + } break; + + case ShaderLanguage::TYPE_MAT4: { + GLfloat mat[16] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; -void ShaderGLES2::set_base_material_tex_index(int p_idx) { + glUniformMatrix4fv(location, 1, GL_FALSE, mat); + + } break; + + case ShaderLanguage::TYPE_SAMPLER2D: { + + } break; + + case ShaderLanguage::TYPE_ISAMPLER2D: { + + } break; + + case ShaderLanguage::TYPE_USAMPLER2D: { + + } break; + + 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; + default: { + ERR_PRINT("ShaderNode type missing, bug?"); + } break; + } + } + } } ShaderGLES2::ShaderGLES2() { diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h index 78e1962f80..2456a83d35 100644 --- a/drivers/gles2/shader_gles2.h +++ b/drivers/gles2/shader_gles2.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -104,6 +104,7 @@ private: Vector<StringName> texture_uniforms; Vector<StringName> custom_uniforms; Vector<CharString> custom_defines; + Set<uint32_t> versions; }; struct Version { @@ -111,7 +112,6 @@ private: GLuint id; GLuint vert_id; GLuint frag_id; - Vector<StringName> uniform_names; GLint *uniform_location; Vector<GLint> texture_uniform_locations; Map<StringName, GLint> custom_uniform_locations; @@ -176,9 +176,6 @@ private: int max_image_units; - Map<uint32_t, Variant> uniform_defaults; - Map<uint32_t, CameraMatrix> uniform_cameras; - Map<StringName, Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > > uniform_values; protected: @@ -211,233 +208,11 @@ public: static _FORCE_INLINE_ ShaderGLES2 *get_active() { return active; } bool bind(); void unbind(); - void bind_uniforms(); inline GLuint get_program() const { return version ? version->id : 0; } void clear_caches(); - _FORCE_INLINE_ void _set_uniform_value(GLint p_uniform, const Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > &value) { - if (p_uniform < 0) - return; - - const Vector<ShaderLanguage::ConstantNode::Value> &values = value.second; - - switch (value.first) { - case ShaderLanguage::TYPE_BOOL: { - glUniform1i(p_uniform, values[0].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC2: { - glUniform2i(p_uniform, values[0].boolean, values[1].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC3: { - glUniform3i(p_uniform, values[0].boolean, values[1].boolean, values[2].boolean); - } break; - - case ShaderLanguage::TYPE_BVEC4: { - glUniform4i(p_uniform, values[0].boolean, values[1].boolean, values[2].boolean, values[3].boolean); - } break; - - case ShaderLanguage::TYPE_INT: { - glUniform1i(p_uniform, values[0].sint); - } break; - - case ShaderLanguage::TYPE_IVEC2: { - glUniform2i(p_uniform, values[0].sint, values[1].sint); - } break; - - case ShaderLanguage::TYPE_IVEC3: { - glUniform3i(p_uniform, values[0].sint, values[1].sint, values[2].sint); - } break; - - case ShaderLanguage::TYPE_IVEC4: { - glUniform4i(p_uniform, values[0].sint, values[1].sint, values[2].sint, values[3].sint); - } break; - - case ShaderLanguage::TYPE_UINT: { - glUniform1i(p_uniform, values[0].uint); - } break; - - case ShaderLanguage::TYPE_UVEC2: { - glUniform2i(p_uniform, values[0].uint, values[1].uint); - } break; - - case ShaderLanguage::TYPE_UVEC3: { - glUniform3i(p_uniform, values[0].uint, values[1].uint, values[2].uint); - } break; - - case ShaderLanguage::TYPE_UVEC4: { - glUniform4i(p_uniform, values[0].uint, values[1].uint, values[2].uint, values[3].uint); - } break; - - case ShaderLanguage::TYPE_FLOAT: { - glUniform1f(p_uniform, values[0].real); - } break; - - case ShaderLanguage::TYPE_VEC2: { - glUniform2f(p_uniform, values[0].real, values[1].real); - } break; - - case ShaderLanguage::TYPE_VEC3: { - glUniform3f(p_uniform, values[0].real, values[1].real, values[2].real); - } break; - - case ShaderLanguage::TYPE_VEC4: { - glUniform4f(p_uniform, values[0].real, values[1].real, values[2].real, values[3].real); - } break; - - case ShaderLanguage::TYPE_MAT2: { - GLfloat mat[4]; - - for (int i = 0; i < 4; i++) { - mat[i] = values[i].real; - } - - glUniformMatrix2fv(p_uniform, 1, GL_FALSE, mat); - } break; - - case ShaderLanguage::TYPE_MAT3: { - GLfloat mat[9]; - - for (int i = 0; i < 9; i++) { - mat[i] = values[i].real; - } - - glUniformMatrix3fv(p_uniform, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_MAT4: { - GLfloat mat[16]; - - for (int i = 0; i < 16; i++) { - mat[i] = values[i].real; - } - - glUniformMatrix4fv(p_uniform, 1, GL_FALSE, mat); - - } break; - - case ShaderLanguage::TYPE_SAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_ISAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_USAMPLER2D: { - - } break; - - case ShaderLanguage::TYPE_SAMPLERCUBE: { - - } break; - } - } - - _FORCE_INLINE_ void _set_uniform_variant(GLint p_uniform, const Variant &p_value) { - - if (p_uniform < 0) - return; // do none - switch (p_value.get_type()) { - - case Variant::BOOL: - case Variant::INT: { - - int val = p_value; - glUniform1i(p_uniform, val); - } break; - case Variant::REAL: { - - real_t val = p_value; - glUniform1f(p_uniform, val); - } break; - case Variant::COLOR: { - - Color val = p_value; - glUniform4f(p_uniform, val.r, val.g, val.b, val.a); - } break; - case Variant::VECTOR2: { - - Vector2 val = p_value; - glUniform2f(p_uniform, val.x, val.y); - } break; - case Variant::VECTOR3: { - - Vector3 val = p_value; - glUniform3f(p_uniform, val.x, val.y, val.z); - } break; - case Variant::PLANE: { - - Plane val = p_value; - glUniform4f(p_uniform, val.normal.x, val.normal.y, val.normal.z, val.d); - } break; - case Variant::QUAT: { - - Quat val = p_value; - glUniform4f(p_uniform, val.x, val.y, val.z, val.w); - } break; - - case Variant::TRANSFORM2D: { - - Transform2D tr = p_value; - GLfloat matrix[16] = { /* build a 16x16 matrix */ - tr.elements[0][0], - tr.elements[0][1], - 0, - 0, - tr.elements[1][0], - tr.elements[1][1], - 0, - 0, - 0, - 0, - 1, - 0, - tr.elements[2][0], - tr.elements[2][1], - 0, - 1 - }; - - glUniformMatrix4fv(p_uniform, 1, false, matrix); - - } break; - case Variant::BASIS: - case Variant::TRANSFORM: { - - Transform tr = p_value; - GLfloat matrix[16] = { /* build a 16x16 matrix */ - tr.basis.elements[0][0], - tr.basis.elements[1][0], - tr.basis.elements[2][0], - 0, - tr.basis.elements[0][1], - tr.basis.elements[1][1], - tr.basis.elements[2][1], - 0, - tr.basis.elements[0][2], - tr.basis.elements[1][2], - tr.basis.elements[2][2], - 0, - tr.origin.x, - tr.origin.y, - tr.origin.z, - 1 - }; - - glUniformMatrix4fv(p_uniform, 1, false, matrix); - } break; - case Variant::OBJECT: { - - } break; - default: { ERR_FAIL(); } // do nothing - } - } - uint32_t create_custom_shader(); void set_custom_shader_code(uint32_t p_code_id, const String &p_vertex, @@ -452,17 +227,7 @@ public: void set_custom_shader(uint32_t p_code_id); void free_custom_shader(uint32_t p_code_id); - void set_uniform_default(int p_idx, const Variant &p_value) { - - if (p_value.get_type() == Variant::NIL) { - - uniform_defaults.erase(p_idx); - } else { - - uniform_defaults[p_idx] = p_value; - } - uniforms_dirty = true; - } + uint32_t get_version_key() const { return conditional_version.version; } // this void* is actually a RasterizerStorageGLES2::Material, but C++ doesn't // like forward declared nested classes. @@ -471,31 +236,9 @@ public: _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) { - - uniform_cameras[p_idx] = p_mat; - uniforms_dirty = true; - } - - _FORCE_INLINE_ void set_texture_uniform(int p_idx, const Variant &p_value) { - - ERR_FAIL_COND(!version); - ERR_FAIL_INDEX(p_idx, version->texture_uniform_locations.size()); - _set_uniform_variant(version->texture_uniform_locations[p_idx], p_value); - } - - _FORCE_INLINE_ GLint get_texture_uniform_location(int p_idx) { - - ERR_FAIL_COND_V(!version, -1); - ERR_FAIL_INDEX_V(p_idx, version->texture_uniform_locations.size(), -1); - return version->texture_uniform_locations[p_idx]; - } - virtual void init() = 0; void finish(); - void set_base_material_tex_index(int p_idx); - void add_custom_define(const String &p_define) { custom_defines.push_back(p_define.utf8()); } diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub index acb93fff8f..d7ae0243e6 100644 --- a/drivers/gles2/shaders/SCsub +++ b/drivers/gles2/shaders/SCsub @@ -6,17 +6,18 @@ if 'GLES2_GLSL' in env['BUILDERS']: env.GLES2_GLSL('copy.glsl'); # env.GLES2_GLSL('resolve.glsl'); env.GLES2_GLSL('canvas.glsl'); -# env.GLES2_GLSL('canvas_shadow.glsl'); + env.GLES2_GLSL('canvas_shadow.glsl'); env.GLES2_GLSL('scene.glsl'); env.GLES2_GLSL('cubemap_filter.glsl'); env.GLES2_GLSL('cube_to_dp.glsl'); # env.GLES2_GLSL('blend_shape.glsl'); # env.GLES2_GLSL('screen_space_reflection.glsl'); -# env.GLES2_GLSL('effect_blur.glsl'); + env.GLES2_GLSL('effect_blur.glsl'); # env.GLES2_GLSL('subsurf_scattering.glsl'); # env.GLES2_GLSL('ssao.glsl'); # env.GLES2_GLSL('ssao_minify.glsl'); # env.GLES2_GLSL('ssao_blur.glsl'); # env.GLES2_GLSL('exposure.glsl'); -# env.GLES2_GLSL('tonemap.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..08548ded17 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -2,21 +2,50 @@ [vertex] #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else -precision mediump float; -precision mediump int; +precision highp float; +precision highp int; #endif uniform highp mat4 projection_matrix; /* clang-format on */ + +#include "stdlib.glsl" + uniform highp mat4 modelview_matrix; uniform highp mat4 extra_matrix; attribute highp vec2 vertex; // attrib:0 attribute vec4 color_attrib; // attrib:3 attribute vec2 uv_attrib; // attrib:4 +#ifdef USE_SKELETON +attribute highp vec4 bone_indices; // attrib:6 +attribute highp vec4 bone_weights; // attrib:7 +#endif + +#ifdef USE_INSTANCING + +attribute highp vec4 instance_xform0; //attrib:8 +attribute highp vec4 instance_xform1; //attrib:9 +attribute highp vec4 instance_xform2; //attrib:10 +attribute highp vec4 instance_color; //attrib:11 + +#ifdef USE_INSTANCE_CUSTOM +attribute highp vec4 instance_custom_data; //attrib:12 +#endif + +#endif + +#ifdef USE_SKELETON +uniform highp sampler2D skeleton_texture; // texunit:-3 +uniform highp ivec2 skeleton_texture_size; +uniform highp mat4 skeleton_transform; +uniform highp mat4 skeleton_transform_inverse; +#endif + varying vec2 uv_interp; varying vec4 color_interp; @@ -31,6 +60,35 @@ uniform vec4 src_rect; uniform highp float time; +#ifdef USE_LIGHTING + +// light matrices +uniform highp mat4 light_matrix; +uniform highp mat4 light_matrix_inverse; +uniform highp mat4 light_local_matrix; +uniform highp mat4 shadow_matrix; +uniform highp vec4 light_color; +uniform highp vec4 light_shadow_color; +uniform highp vec2 light_pos; +uniform highp float shadowpixel_size; +uniform highp float shadow_gradient; +uniform highp float light_height; +uniform highp float light_outside_alpha; +uniform highp float shadow_distance_mult; + +varying vec4 light_uv_interp; +varying vec2 transformed_light_uv; +varying vec4 local_rot; + +#ifdef USE_SHADOWS +varying highp vec2 pos; +#endif + +const bool at_light_pass = true; +#else +const bool at_light_pass = false; +#endif + /* clang-format off */ VERTEX_SHADER_GLOBALS @@ -49,13 +107,29 @@ vec2 select(vec2 a, vec2 b, bvec2 c) { void main() { vec4 color = color_attrib; + vec2 uv; + +#ifdef USE_INSTANCING + 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; + +#ifdef USE_INSTANCE_CUSTOM + vec4 instance_custom = instance_custom_data; +#else + vec4 instance_custom = vec4(0.0); +#endif + +#else + mat4 extra_matrix_instance = extra_matrix; + vec4 instance_custom = vec4(0.0); +#endif #ifdef USE_TEXTURE_RECT if (dst_rect.z < 0.0) { // Transpose is encoded as negative dst_rect.z - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex.yx; + uv = src_rect.xy + abs(src_rect.zw) * vertex.yx; } else { - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex; + uv = src_rect.xy + abs(src_rect.zw) * vertex; } vec4 outvec = vec4(0.0, 0.0, 0.0, 1.0); @@ -72,12 +146,7 @@ void main() { #else vec4 outvec = vec4(vertex.xy, 0.0, 1.0); -#ifdef USE_UV_ATTRIBUTE - uv_interp = uv_attrib; -#else - uv_interp = vertex.xy; -#endif - + uv = uv_attrib; #endif { @@ -89,21 +158,107 @@ VERTEX_SHADER_CODE /* clang-format on */ } +#if !defined(SKIP_TRANSFORM_USED) + outvec = extra_matrix_instance * 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; + // precision issue on some hardware creates artifacts within texture + // offset uv by a small amount to avoid + uv += 1e-5; +#endif + +#ifdef USE_SKELETON + + // look up transform from the "pose texture" + if (bone_weights != vec4(0.0)) { + + highp mat4 bone_transform = mat4(0.0); + + for (int i = 0; i < 4; i++) { + ivec2 tex_ofs = ivec2(int(bone_indices[i]) * 2, 0); + + highp mat4 b = mat4( + texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(0, 0)), + texel2DFetch(skeleton_texture, skeleton_texture_size, tex_ofs + ivec2(1, 0)), + vec4(0.0, 0.0, 1.0, 0.0), + vec4(0.0, 0.0, 0.0, 1.0)); + + bone_transform += b * bone_weights[i]; + } + + mat4 bone_matrix = skeleton_transform * transpose(bone_transform) * skeleton_transform_inverse; + + outvec = bone_matrix * outvec; + } + +#endif + + uv_interp = uv; + gl_Position = projection_matrix * outvec; + +#ifdef USE_LIGHTING + + light_uv_interp.xy = (light_matrix * outvec).xy; + light_uv_interp.zw = (light_local_matrix * outvec).xy; + + transformed_light_uv = (mat3(light_matrix_inverse) * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping + +#ifdef USE_SHADOWS + pos = outvec.xy; +#endif + + 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); +#endif + +#endif } /* clang-format off */ [fragment] +// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. +// Do not copy these defines in the vertex section. +#ifndef USE_GLES_OVER_GL +#ifdef GL_EXT_shader_texture_lod +#extension GL_EXT_shader_texture_lod : enable +#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) +#endif +#endif // !USE_GLES_OVER_GL + +#ifdef GL_ARB_shader_texture_lod +#extension GL_ARB_shader_texture_lod : enable +#endif + +#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) +#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) +#endif + #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else precision mediump float; precision mediump int; #endif +#endif + +#include "stdlib.glsl" uniform sampler2D color_texture; // texunit:-1 /* clang-format on */ @@ -119,7 +274,7 @@ uniform vec4 final_modulate; #ifdef SCREEN_TEXTURE_USED -uniform sampler2D screen_texture; // texunit:-3 +uniform sampler2D screen_texture; // texunit:-4 #endif @@ -129,30 +284,325 @@ uniform vec2 screen_pixel_size; #endif +#ifdef USE_LIGHTING + +uniform highp mat4 light_matrix; +uniform highp mat4 light_local_matrix; +uniform highp mat4 shadow_matrix; +uniform highp vec4 light_color; +uniform highp vec4 light_shadow_color; +uniform highp vec2 light_pos; +uniform highp float shadowpixel_size; +uniform highp float shadow_gradient; +uniform highp float light_height; +uniform highp float light_outside_alpha; +uniform highp float shadow_distance_mult; + +uniform lowp sampler2D light_texture; // texunit:-4 +varying vec4 light_uv_interp; +varying vec2 transformed_light_uv; + +varying vec4 local_rot; + +#ifdef USE_SHADOWS + +uniform highp sampler2D shadow_texture; // texunit:-5 +varying highp vec2 pos; + +#endif + +const bool at_light_pass = true; +#else +const bool at_light_pass = false; +#endif + +uniform bool use_default_normal; + /* clang-format off */ FRAGMENT_SHADER_GLOBALS /* clang-format on */ +void light_compute( + inout vec4 light, + inout vec2 light_vec, + inout float light_height, + inout vec4 light_color, + vec2 light_uv, + inout vec4 shadow_color, + inout vec2 shadow_vec, + vec3 normal, + vec2 uv, +#if defined(SCREEN_UV_USED) + vec2 screen_uv, +#endif + vec4 color) { + +#if defined(USE_LIGHT_SHADER_CODE) + + /* clang-format off */ + +LIGHT_SHADER_CODE + + /* clang-format on */ + +#endif +} + void main() { vec4 color = color_interp; + vec2 uv = uv_interp; +#ifdef USE_FORCE_REPEAT + //needs to use this to workaround GLES2/WebGL1 forcing tiling that textures that don't support it + uv = mod(uv, vec2(1.0, 1.0)); +#endif - color *= texture2D(color_texture, uv_interp); +#if !defined(COLOR_USED) + //default behavior, texture by color + color *= texture2D(color_texture, uv); +#endif #ifdef SCREEN_UV_USED vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; #endif + + vec3 normal; + +#if defined(NORMAL_USED) + + bool normal_used = true; +#else + bool normal_used = false; +#endif + + if (use_default_normal) { + normal.xy = texture2D(normal_texture, uv).xy * 2.0 - 1.0; + normal.z = sqrt(1.0 - dot(normal.xy, normal.xy)); + normal_used = true; + } else { + normal = vec3(0.0, 0.0, 1.0); + } + { + float normal_depth = 1.0; + +#if defined(NORMALMAP_USED) + vec3 normal_map = vec3(0.0, 0.0, 1.0); + normal_used = true; +#endif + /* clang-format off */ FRAGMENT_SHADER_CODE /* clang-format on */ - } +#if defined(NORMALMAP_USED) + normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth); +#endif + } color *= final_modulate; +#ifdef USE_LIGHTING + + vec2 light_vec = transformed_light_uv; + vec2 shadow_vec = transformed_light_uv; + + if (normal_used) { + normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy; + } + + float att = 1.0; + + vec2 light_uv = light_uv_interp.xy; + vec4 light = texture2D(light_texture, light_uv); + + if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) { + color.a *= light_outside_alpha; //invisible + + } else { + float real_light_height = light_height; + vec4 real_light_color = light_color; + vec4 real_light_shadow_color = light_shadow_color; + +#if defined(USE_LIGHT_SHADER_CODE) + //light is written by the light shader + light_compute( + light, + light_vec, + real_light_height, + real_light_color, + light_uv, + real_light_shadow_color, + shadow_vec, + normal, + uv, +#if defined(SCREEN_UV_USED) + screen_uv, +#endif + color); +#endif + + light *= real_light_color; + + if (normal_used) { + vec3 light_normal = normalize(vec3(light_vec, -real_light_height)); + light *= max(dot(-light_normal, normal), 0.0); + } + + color *= light; + +#ifdef USE_SHADOWS + +#ifdef SHADOW_VEC_USED + mat3 inverse_light_matrix = mat3(light_matrix); + inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); + inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); + inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); + shadow_vec = (inverse_light_matrix * vec3(shadow_vec, 0.0)).xy; +#else + shadow_vec = light_uv_interp.zw; +#endif + + float angle_to_light = -atan(shadow_vec.x, shadow_vec.y); + float PI = 3.14159265358979323846264; + /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays + float ang*/ + + float su, sz; + + float abs_angle = abs(angle_to_light); + vec2 point; + float sh; + if (abs_angle < 45.0 * PI / 180.0) { + point = shadow_vec; + sh = 0.0 + (1.0 / 8.0); + } else if (abs_angle > 135.0 * PI / 180.0) { + point = -shadow_vec; + sh = 0.5 + (1.0 / 8.0); + } else if (angle_to_light > 0.0) { + + point = vec2(shadow_vec.y, -shadow_vec.x); + sh = 0.25 + (1.0 / 8.0); + } else { + + point = vec2(-shadow_vec.y, shadow_vec.x); + sh = 0.75 + (1.0 / 8.0); + } + + highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0); + s.xyz /= s.w; + su = s.x * 0.5 + 0.5; + sz = s.z * 0.5 + 0.5; + //sz=lightlength(light_vec); + + highp float shadow_attenuation = 0.0; + +#ifdef USE_RGBA_SHADOWS +#define SHADOW_DEPTH(m_tex, m_uv) dot(texture2D((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) + +#else + +#define SHADOW_DEPTH(m_tex, m_uv) (texture2D((m_tex), (m_uv)).r) + +#endif + +#ifdef SHADOW_USE_GRADIENT + + /* clang-format off */ + /* GLSL es 100 doesn't support line continuation characters(backslashes) */ +#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); } + +#else + +#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); shadow_attenuation += step(sz, sd); } + /* clang-format on */ + +#endif + +#ifdef SHADOW_FILTER_NEAREST + + SHADOW_TEST(su); + +#endif + +#ifdef SHADOW_FILTER_PCF3 + + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + shadow_attenuation /= 3.0; + +#endif + +#ifdef SHADOW_FILTER_PCF5 + + SHADOW_TEST(su + shadowpixel_size * 2.0); + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + SHADOW_TEST(su - shadowpixel_size * 2.0); + shadow_attenuation /= 5.0; + +#endif + +#ifdef SHADOW_FILTER_PCF7 + + SHADOW_TEST(su + shadowpixel_size * 3.0); + SHADOW_TEST(su + shadowpixel_size * 2.0); + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + SHADOW_TEST(su - shadowpixel_size * 2.0); + SHADOW_TEST(su - shadowpixel_size * 3.0); + shadow_attenuation /= 7.0; + +#endif + +#ifdef SHADOW_FILTER_PCF9 + + SHADOW_TEST(su + shadowpixel_size * 4.0); + SHADOW_TEST(su + shadowpixel_size * 3.0); + SHADOW_TEST(su + shadowpixel_size * 2.0); + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + SHADOW_TEST(su - shadowpixel_size * 2.0); + SHADOW_TEST(su - shadowpixel_size * 3.0); + SHADOW_TEST(su - shadowpixel_size * 4.0); + shadow_attenuation /= 9.0; + +#endif + +#ifdef SHADOW_FILTER_PCF13 + + SHADOW_TEST(su + shadowpixel_size * 6.0); + SHADOW_TEST(su + shadowpixel_size * 5.0); + SHADOW_TEST(su + shadowpixel_size * 4.0); + SHADOW_TEST(su + shadowpixel_size * 3.0); + SHADOW_TEST(su + shadowpixel_size * 2.0); + SHADOW_TEST(su + shadowpixel_size); + SHADOW_TEST(su); + SHADOW_TEST(su - shadowpixel_size); + SHADOW_TEST(su - shadowpixel_size * 2.0); + SHADOW_TEST(su - shadowpixel_size * 3.0); + SHADOW_TEST(su - shadowpixel_size * 4.0); + SHADOW_TEST(su - shadowpixel_size * 5.0); + SHADOW_TEST(su - shadowpixel_size * 6.0); + shadow_attenuation /= 13.0; + +#endif + + //color *= shadow_attenuation; + color = mix(real_light_shadow_color, color, shadow_attenuation); +//use shadows +#endif + } + +//use lighting +#endif + gl_FragColor = color; } diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl index e3c8140e31..7a5ba4f571 100644 --- a/drivers/gles2/shaders/canvas_shadow.glsl +++ b/drivers/gles2/shaders/canvas_shadow.glsl @@ -1,15 +1,24 @@ /* clang-format off */ [vertex] +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +attribute highp vec3 vertex; // attrib:0 + uniform highp mat4 projection_matrix; /* clang-format on */ uniform highp mat4 light_matrix; uniform highp mat4 world_matrix; uniform highp float distance_norm; -layout(location = 0) in highp vec3 vertex; - -out highp vec4 position_interp; +varying highp vec4 position_interp; void main() { @@ -20,31 +29,34 @@ void main() { /* clang-format off */ [fragment] -in highp vec4 position_interp; -/* clang-format on */ - -#ifdef USE_RGBA_SHADOWS - -layout(location = 0) out lowp vec4 distance_buf; - +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp #else - -layout(location = 0) out highp float distance_buf; - +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; #endif +#endif + +varying highp vec4 position_interp; +/* clang-format on */ void main() { - highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; //bias; + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias #ifdef USE_RGBA_SHADOWS - highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); - comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); - distance_buf = comp; + highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); + comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); + gl_FragColor = comp; #else - distance_buf = depth; - + gl_FragColor = vec4(depth); #endif } diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl index 16bbde196d..aa967115da 100644 --- a/drivers/gles2/shaders/copy.glsl +++ b/drivers/gles2/shaders/copy.glsl @@ -2,11 +2,12 @@ [vertex] #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else -precision mediump float; -precision mediump int; +precision highp float; +precision highp int; #endif attribute highp vec4 vertex_attrib; // attrib:0 @@ -27,14 +28,23 @@ varying vec2 uv_interp; #endif varying vec2 uv2_interp; +// These definitions are here because the shader-wrapper builder does +// not understand `#elif defined()` +#ifdef USE_DISPLAY_TRANSFORM +#endif + #ifdef USE_COPY_SECTION -uniform vec4 copy_section; +uniform highp vec4 copy_section; +#elif defined(USE_DISPLAY_TRANSFORM) +uniform highp mat4 display_transform; #endif 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 @@ -45,6 +55,8 @@ void main() { #ifdef USE_COPY_SECTION uv_interp = copy_section.xy + uv_interp * copy_section.zw; gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; +#elif defined(USE_DISPLAY_TRANSFORM) + uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy; #endif } @@ -54,12 +66,18 @@ void main() { #define M_PI 3.14159265359 #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else precision mediump float; precision mediump int; #endif +#endif #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) varying vec3 cube_interp; @@ -68,12 +86,21 @@ 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 uniform sampler2D source; // texunit:0 #endif +#ifdef SEP_CBCR_TEXTURE +uniform sampler2D CbCr; //texunit:1 +#endif + varying vec2 uv2_interp; #ifdef USE_MULTIPLIER @@ -85,6 +112,7 @@ uniform float custom_alpha; #endif #if defined(USE_PANORAMA) || defined(USE_ASYM_PANO) +uniform highp mat4 sky_transform; vec4 texturePanorama(sampler2D pano, vec3 normal) { @@ -106,14 +134,50 @@ void main() { #ifdef USE_PANORAMA - vec4 color = texturePanorama(source, normalize(cube_interp)); + vec3 cube_normal = normalize(cube_interp); + cube_normal.z = -cube_normal.z; + cube_normal = mat3(sky_transform) * cube_normal; + cube_normal.z = -cube_normal.z; + + vec4 color = texturePanorama(source, cube_normal); + +#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. + // Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted. + // 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 = -1.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(sky_transform) * 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)); +#elif defined(SEP_CBCR_TEXTURE) + vec4 color; + color.r = texture2D(source, uv_interp).r; + color.gb = texture2D(CbCr, uv_interp).rg - vec2(0.5, 0.5); + color.a = 1.0; #else vec4 color = texture2D(source, uv_interp); #endif +#ifdef YCBCR_TO_RGB + // YCbCr -> RGB conversion + + // Using BT.601, which is the standard for SDTV is provided as a reference + color.rgb = mat3( + vec3(1.00000, 1.00000, 1.00000), + vec3(0.00000, -0.34413, 1.77200), + vec3(1.40200, -0.71414, 0.00000)) * + color.rgb; +#endif + #ifdef USE_NO_ALPHA color.a = 1.0; #endif diff --git a/drivers/gles2/shaders/cube_to_dp.glsl b/drivers/gles2/shaders/cube_to_dp.glsl index 3d24c36336..769908c3b4 100644 --- a/drivers/gles2/shaders/cube_to_dp.glsl +++ b/drivers/gles2/shaders/cube_to_dp.glsl @@ -2,6 +2,7 @@ [vertex] #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else @@ -25,12 +26,18 @@ void main() { [fragment] #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else precision mediump float; precision mediump int; #endif +#endif uniform highp samplerCube source_cube; //texunit:0 /* clang-format on */ diff --git a/drivers/gles2/shaders/cubemap_filter.glsl b/drivers/gles2/shaders/cubemap_filter.glsl index 2a1ad8d8f2..db3d8b3a1b 100644 --- a/drivers/gles2/shaders/cubemap_filter.glsl +++ b/drivers/gles2/shaders/cubemap_filter.glsl @@ -2,11 +2,12 @@ [vertex] #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else -precision mediump float; -precision mediump int; +precision highp float; +precision highp int; #endif attribute highp vec2 vertex; // attrib:0 @@ -24,21 +25,40 @@ void main() { /* clang-format off */ [fragment] +// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. +// Do not copy these defines in the vertex section. +#ifndef USE_GLES_OVER_GL +#ifdef GL_EXT_shader_texture_lod +#extension GL_EXT_shader_texture_lod : enable +#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) +#endif +#endif // !USE_GLES_OVER_GL + +#ifdef GL_ARB_shader_texture_lod #extension GL_ARB_shader_texture_lod : enable +#endif -#ifndef GL_ARB_shader_texture_lod -#define texture2DLod(img, coord, lod) texture2D(img, coord) -#define textureCubeLod(img, coord, lod) textureCube(img, coord) +#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) +#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) #endif #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else precision mediump float; precision mediump int; #endif +#endif + #ifdef USE_SOURCE_PANORAMA uniform sampler2D source_panorama; //texunit:0 #else @@ -116,7 +136,13 @@ vec3 texelCoordToVec(vec2 uv, int faceID) { faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2]. - vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2]; + vec3 result; + for (int i = 0; i < 6; i++) { + if (i == faceID) { + result = (faceUvVectors[i][0] * uv.x) + (faceUvVectors[i][1] * uv.y) + faceUvVectors[i][2]; + break; + } + } return normalize(result); } @@ -159,6 +185,18 @@ void main() { vec2 uv = (uv_interp * 2.0) - 1.0; vec3 N = texelCoordToVec(uv, face_id); +#ifdef USE_DIRECT_WRITE + +#ifdef USE_SOURCE_PANORAMA + + gl_FragColor = vec4(texturePanorama(source_panorama, N).rgb, 1.0); +#else + + gl_FragColor = vec4(textureCube(source_cube, N).rgb, 1.0); +#endif //USE_SOURCE_PANORAMA + +#else + vec4 sum = vec4(0.0); for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) { @@ -167,18 +205,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 +227,9 @@ 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); +#endif } diff --git a/drivers/gles2/shaders/effect_blur.glsl b/drivers/gles2/shaders/effect_blur.glsl index a531802c75..b28d78a6ca 100644 --- a/drivers/gles2/shaders/effect_blur.glsl +++ b/drivers/gles2/shaders/effect_blur.glsl @@ -1,11 +1,20 @@ /* clang-format off */ [vertex] -layout(location = 0) in highp vec4 vertex_attrib; +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +attribute vec2 vertex_attrib; // attrib:0 /* clang-format on */ -layout(location = 4) in vec2 uv_in; +attribute vec2 uv_in; // attrib:4 -out vec2 uv_interp; +varying vec2 uv_interp; #ifdef USE_BLUR_SECTION @@ -16,7 +25,7 @@ uniform vec4 blur_section; void main() { uv_interp = uv_in; - gl_Position = vertex_attrib; + gl_Position = vec4(vertex_attrib, 0.0, 1.0); #ifdef USE_BLUR_SECTION uv_interp = blur_section.xy + uv_interp * blur_section.zw; @@ -27,29 +36,46 @@ void main() { /* clang-format off */ [fragment] -#if !defined(GLES_OVER_GL) +// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. +// Do not copy these defines in the vertex section. +#ifndef USE_GLES_OVER_GL +#ifdef GL_EXT_shader_texture_lod +#extension GL_EXT_shader_texture_lod : enable +#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) +#endif +#endif // !USE_GLES_OVER_GL + +#ifdef GL_ARB_shader_texture_lod +#extension GL_ARB_shader_texture_lod : enable +#endif + +#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) +#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) +#endif + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else precision mediump float; +precision mediump int; +#endif #endif -in vec2 uv_interp; +varying vec2 uv_interp; /* clang-format on */ uniform sampler2D source_color; //texunit:0 -#ifdef SSAO_MERGE -uniform sampler2D source_ssao; //texunit:1 -#endif - uniform float lod; uniform vec2 pixel_size; -layout(location = 0) out vec4 frag_color; - -#ifdef SSAO_MERGE - -uniform vec4 ssao_color; - -#endif - #if defined(GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL) uniform float glow_strength; @@ -58,6 +84,7 @@ uniform float glow_strength; #if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR) +#ifdef USE_GLES_OVER_GL #ifdef DOF_QUALITY_LOW const int dof_kernel_size = 5; const int dof_kernel_from = 2; @@ -76,6 +103,7 @@ const int dof_kernel_size = 21; const int dof_kernel_from = 10; const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174); #endif +#endif uniform sampler2D dof_source_depth; //texunit:1 uniform float dof_begin; @@ -83,24 +111,11 @@ uniform float dof_end; uniform vec2 dof_dir; uniform float dof_radius; -#ifdef DOF_NEAR_BLUR_MERGE - -uniform sampler2D source_dof_original; //texunit:2 -#endif - #endif #ifdef GLOW_FIRST_PASS -uniform float exposure; -uniform float white; - -#ifdef GLOW_USE_AUTO_EXPOSURE - -uniform highp sampler2D source_auto_exposure; //texunit:1 -uniform highp float auto_exposure_grey; - -#endif +uniform highp float luminance_cap; uniform float glow_bloom; uniform float glow_hdr_threshold; @@ -113,59 +128,95 @@ uniform float camera_z_near; void main() { -#ifdef GAUSSIAN_HORIZONTAL +#ifdef GLOW_GAUSSIAN_HORIZONTAL vec2 pix_size = pixel_size; pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.214607; - color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.157305; - color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.071303; - color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.157305; - color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.071303; - frag_color = color; + vec4 color = texture2DLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.174938; + color += texture2DLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.165569; + color += texture2DLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.140367; + color += texture2DLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.106595; + color += texture2DLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.165569; + color += texture2DLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.140367; + color += texture2DLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.106595; + color *= glow_strength; + gl_FragColor = color; #endif -#ifdef GAUSSIAN_VERTICAL - vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.38774; - color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.24477; - color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.06136; - color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.24477; - color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.06136; - frag_color = color; +#ifdef GLOW_GAUSSIAN_VERTICAL + vec4 color = texture2DLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.288713; + color += texture2DLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.233062; + color += texture2DLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.122581; + color += texture2DLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062; + color += texture2DLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581; + color *= glow_strength; + gl_FragColor = color; #endif - //glow uses larger sigma for a more rounded blur effect +#ifndef USE_GLES_OVER_GL +#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR) -#ifdef GLOW_GAUSSIAN_HORIZONTAL - vec2 pix_size = pixel_size; - pix_size *= 0.5; //reading from larger buffer, so use more samples - vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.174938; - color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.165569; - color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.140367; - color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.106595; - color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.165569; - color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.140367; - color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.106595; - color *= glow_strength; - frag_color = color; +#ifdef DOF_QUALITY_LOW + const int dof_kernel_size = 5; + const int dof_kernel_from = 2; + float dof_kernel[5]; + dof_kernel[0] = 0.153388; + dof_kernel[1] = 0.221461; + dof_kernel[2] = 0.250301; + dof_kernel[3] = 0.221461; + dof_kernel[4] = 0.153388; #endif -#ifdef GLOW_GAUSSIAN_VERTICAL - vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.288713; - color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.233062; - color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.122581; - color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062; - color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581; - color *= glow_strength; - frag_color = color; +#ifdef DOF_QUALITY_MEDIUM + const int dof_kernel_size = 11; + const int dof_kernel_from = 5; + float dof_kernel[11]; + dof_kernel[0] = 0.055037; + dof_kernel[1] = 0.072806; + dof_kernel[2] = 0.090506; + dof_kernel[3] = 0.105726; + dof_kernel[4] = 0.116061; + dof_kernel[5] = 0.119726; + dof_kernel[6] = 0.116061; + dof_kernel[7] = 0.105726; + dof_kernel[8] = 0.090506; + dof_kernel[9] = 0.072806; + dof_kernel[10] = 0.055037; #endif +#ifdef DOF_QUALITY_HIGH + const int dof_kernel_size = 21; + const int dof_kernel_from = 10; + float dof_kernel[21]; + dof_kernel[0] = 0.028174; + dof_kernel[1] = 0.032676; + dof_kernel[2] = 0.037311; + dof_kernel[3] = 0.041944; + dof_kernel[4] = 0.046421; + dof_kernel[5] = 0.050582; + dof_kernel[6] = 0.054261; + dof_kernel[7] = 0.057307; + dof_kernel[8] = 0.059587; + dof_kernel[9] = 0.060998; + dof_kernel[10] = 0.061476; + dof_kernel[11] = 0.060998; + dof_kernel[12] = 0.059587; + dof_kernel[13] = 0.057307; + dof_kernel[14] = 0.054261; + dof_kernel[15] = 0.050582; + dof_kernel[16] = 0.046421; + dof_kernel[17] = 0.041944; + dof_kernel[18] = 0.037311; + dof_kernel[19] = 0.032676; + dof_kernel[20] = 0.028174; +#endif +#endif +#endif //!USE_GLES_OVER_GL + #ifdef DOF_FAR_BLUR vec4 color_accum = vec4(0.0); - float depth = textureLod(dof_source_depth, uv_interp, 0.0).r; + float depth = texture2DLod(dof_source_depth, uv_interp, 0.0).r; depth = depth * 2.0 - 1.0; #ifdef USE_ORTHOGONAL_PROJECTION depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; @@ -183,17 +234,17 @@ void main() { float tap_k = dof_kernel[i]; - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; + float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r; tap_depth = tap_depth * 2.0 - 1.0; #ifdef USE_ORTHOGONAL_PROJECTION tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; #else tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near)); #endif - float tap_amount = mix(smoothstep(dof_begin, dof_end, tap_depth), 1.0, int_ofs == 0); + float tap_amount = int_ofs == 0 ? 1.0 : smoothstep(dof_begin, dof_end, tap_depth); tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect - vec4 tap_color = textureLod(source_color, tap_uv, 0.0) * tap_k; + vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0) * tap_k; k_accum += tap_k * tap_amount; color_accum += tap_color * tap_amount; @@ -203,7 +254,7 @@ void main() { color_accum /= k_accum; } - frag_color = color_accum; ///k_accum; + gl_FragColor = color_accum; ///k_accum; #endif @@ -211,19 +262,19 @@ void main() { vec4 color_accum = vec4(0.0); - float max_accum = 0; + float max_accum = 0.0; for (int i = 0; i < dof_kernel_size; i++) { int int_ofs = i - dof_kernel_from; vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius; - float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from)); + float ofs_influence = max(0.0, 1.0 - abs(float(int_ofs)) / float(dof_kernel_from)); float tap_k = dof_kernel[i]; - vec4 tap_color = textureLod(source_color, tap_uv, 0.0); + vec4 tap_color = texture2DLod(source_color, tap_uv, 0.0); - float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r; + float tap_depth = texture2D(dof_source_depth, tap_uv, 0.0).r; tap_depth = tap_depth * 2.0 - 1.0; #ifdef USE_ORTHOGONAL_PROJECTION tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0; @@ -246,46 +297,16 @@ void main() { color_accum.a = max(color_accum.a, sqrt(max_accum)); -#ifdef DOF_NEAR_BLUR_MERGE - - vec4 original = textureLod(source_dof_original, uv_interp, 0.0); - color_accum = mix(original, color_accum, color_accum.a); - -#endif - -#ifndef DOF_NEAR_FIRST_TAP - //color_accum=vec4(vec3(color_accum.a),1.0); -#endif - frag_color = color_accum; + gl_FragColor = color_accum; #endif #ifdef GLOW_FIRST_PASS -#ifdef GLOW_USE_AUTO_EXPOSURE - - frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / auto_exposure_grey; -#endif - frag_color *= exposure; - - float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); + float luminance = max(gl_FragColor.r, max(gl_FragColor.g, gl_FragColor.b)); float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom); - frag_color *= feedback; - -#endif - -#ifdef SIMPLE_COPY - vec4 color = textureLod(source_color, uv_interp, 0.0); - frag_color = color; -#endif - -#ifdef SSAO_MERGE - - vec4 color = textureLod(source_color, uv_interp, 0.0); - float ssao = textureLod(source_ssao, uv_interp, 0.0).r; - - frag_color = vec4(mix(color.rgb, color.rgb * mix(ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0); + gl_FragColor = min(gl_FragColor * feedback, vec4(luminance_cap)); #endif } diff --git a/drivers/gles2/shaders/lens_distorted.glsl b/drivers/gles2/shaders/lens_distorted.glsl new file mode 100644 index 0000000000..f4ff80ba9a --- /dev/null +++ b/drivers/gles2/shaders/lens_distorted.glsl @@ -0,0 +1,85 @@ +/* clang-format off */ +[vertex] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +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] + +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif + +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 da4c3a84f1..57c2d886b3 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -2,6 +2,7 @@ [vertex] #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else @@ -9,12 +10,15 @@ precision highp float; precision highp int; #endif +/* clang-format on */ #include "stdlib.glsl" +/* clang-format off */ #define SHADER_IS_SRGB true #define M_PI 3.14159265359 + // // attributes // @@ -27,15 +31,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 @@ -43,9 +47,9 @@ attribute vec2 uv2_attrib; // attrib:5 #ifdef USE_SKELETON_SOFTWARE -attribute highp vec4 bone_transform_row_0; // attrib:8 -attribute highp vec4 bone_transform_row_1; // attrib:9 -attribute highp vec4 bone_transform_row_2; // attrib:10 +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 @@ -74,16 +78,16 @@ attribute highp vec4 instance_custom_data; // attrib:12 // 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; -uniform float normal_mult; +uniform highp vec2 viewport_size; #ifdef RENDER_DEPTH uniform float light_bias; @@ -94,6 +98,10 @@ uniform float light_normal_bias; // varyings // +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) +varying highp vec4 position_interp; +#endif + varying highp vec3 vertex_interp; varying vec3 normal_interp; @@ -102,15 +110,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 @@ -130,11 +138,6 @@ uniform highp float shadow_dual_paraboloid_render_side; #if defined(USE_SHADOW) && defined(USE_LIGHTING) -#ifdef LIGHT_MODE_DIRECTIONAL -uniform highp sampler2D light_directional_shadow; // texunit:-3 -uniform highp vec4 light_split_offsets; -#endif - uniform highp mat4 light_shadow_matrix; varying highp vec4 shadow_coord; @@ -160,22 +163,23 @@ varying highp vec3 diffuse_interp; varying highp vec3 specular_interp; // general for all lights -uniform vec4 light_color; -uniform float light_specular; +uniform highp vec4 light_color; +uniform highp vec4 shadow_color; +uniform highp float light_specular; // directional -uniform vec3 light_direction; +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_range; +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; void light_compute( vec3 N, @@ -251,17 +255,71 @@ void light_compute( 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); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); 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; + specular_interp += specular_brdf_NL * light_color * attenuation * (1.0 / M_PI); } } #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; @@ -277,38 +335,42 @@ void main() { vec4(0.0, 0.0, 0.0, 1.0)); world_matrix = world_matrix * transpose(m); } + #endif - vec3 normal = normal_attrib * normal_mult; + vec3 normal = normal_attrib; #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) vec3 tangent = tangent_attrib.xyz; - tangent *= normal_mult; float binormalf = tangent_attrib.a; 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 +#if defined(OVERRIDE_POSITION) + highp vec4 position; +#endif + #if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) vertex = world_matrix * vertex; 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 @@ -344,7 +406,8 @@ void main() { #endif - world_matrix = bone_transform * world_matrix; + world_matrix = world_matrix * bone_transform; + #endif #ifdef USE_INSTANCING @@ -354,9 +417,12 @@ void main() { #endif - mat4 modelview = camera_matrix * world_matrix; + mat4 local_projection_matrix = projection_matrix; + + mat4 modelview = camera_inverse_matrix * world_matrix; float roughness = 1.0; +#define projection_matrix local_projection_matrix #define world_transform world_matrix { @@ -381,11 +447,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 @@ -438,10 +504,15 @@ VERTEX_SHADER_CODE float normalized_distance = light_length / light_range; - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); + if (normalized_distance < 1.0) { - vec3 attenuation = vec3(omni_attenuation); - light_att = vec3(omni_attenuation); + 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); @@ -453,17 +524,30 @@ VERTEX_SHADER_CODE float light_length = length(light_rel_vec); float normalized_distance = light_length / light_range; - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); - vec3 spot_dir = light_direction; + 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 spot_cutoff = light_spot_angle; - 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)); + float angle = dot(-normalize(light_rel_vec), spot_dir); - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + 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); + } - light_att = vec3(spot_attenuation); L = normalize(light_rel_vec); #endif @@ -492,30 +576,132 @@ VERTEX_SHADER_CODE #if defined(LIGHT_USE_PSSM4) shadow_coord3 = light_shadow_matrix3 * vi4; - 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) * fog_color_base.a; + } +#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 + +#if defined(OVERRIDE_POSITION) + gl_Position = position; +#else gl_Position = projection_matrix * vec4(vertex_interp, 1.0); +#endif + +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) + position_interp = gl_Position; +#endif } /* clang-format off */ [fragment] + +// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. +// Do not copy these defines in the vertex section. +#ifndef USE_GLES_OVER_GL +#ifdef GL_EXT_shader_texture_lod +#extension GL_EXT_shader_texture_lod : enable +#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) +#endif +#endif // !USE_GLES_OVER_GL + +#ifdef GL_ARB_shader_texture_lod #extension GL_ARB_shader_texture_lod : enable +#endif -#ifndef GL_ARB_shader_texture_lod -#define texture2DLod(img, coord, lod) texture2D(img, coord) -#define textureCubeLod(img, coord, lod) textureCube(img, coord) +#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) +#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) #endif #ifdef USE_GLES_OVER_GL +#define lowp #define mediump #define highp #else -precision mediump float; +#if defined(USE_HIGHP_PRECISION) +precision highp float; precision highp int; +#else +precision mediump float; +precision mediump int; +#endif #endif #include "stdlib.glsl" @@ -527,17 +713,19 @@ precision highp int; // 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 +uniform highp vec2 viewport_size; + +#if defined(SCREEN_UV_USED) uniform vec2 screen_pixel_size; #endif @@ -547,17 +735,179 @@ uniform vec2 screen_pixel_size; #if defined(SCREEN_TEXTURE_USED) uniform highp sampler2D screen_texture; //texunit:-4 #endif +#if defined(DEPTH_TEXTURE_USED) +uniform highp sampler2D depth_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; #endif +uniform vec4 bg_color; uniform float bg_energy; uniform float ambient_sky_contribution; @@ -566,33 +916,38 @@ uniform float ambient_energy; #ifdef USE_LIGHTING +uniform highp vec4 shadow_color; + #ifdef USE_VERTEX_LIGHTING //get from vertex varying highp vec3 diffuse_interp; varying highp vec3 specular_interp; +uniform highp vec3 light_direction; //may be used by fog, so leave here + #else //done in fragment // general for all lights -uniform vec4 light_color; -uniform float light_specular; +uniform highp vec4 light_color; + +uniform highp float light_specular; // directional -uniform vec3 light_direction; +uniform highp vec3 light_direction; // omni -uniform vec3 light_position; +uniform highp vec3 light_position; -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 //this is needed outside above if because dual paraboloid wants it -uniform float light_range; +uniform highp float light_range; #ifdef USE_SHADOW @@ -632,6 +987,10 @@ uniform vec4 light_clamp; // varyings // +#if defined(RENDER_DEPTH) && defined(USE_RGBA_SHADOWS) +varying highp vec4 position_interp; +#endif + varying highp vec3 vertex_interp; varying vec3 normal_interp; @@ -640,24 +999,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 */ @@ -690,6 +1050,7 @@ varying highp float dp_clip; // 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) @@ -702,6 +1063,13 @@ float G_GGX_2cos(float cos_theta_m, float alpha) { // 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) { + return 0.5 / mix(2.0 * cos_theta_l * cos_theta_v, cos_theta_l + cos_theta_v, alpha); +} float D_GGX(float cos_theta_m, float alpha) { float alpha2 = alpha * alpha; @@ -709,6 +1077,7 @@ float D_GGX(float cos_theta_m, float alpha) { 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); @@ -716,14 +1085,30 @@ float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, fl 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); } +*/ -float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; +// 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); + return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); */ } float SchlickFresnel(float u) { @@ -752,13 +1137,15 @@ void light_compute( 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) { + inout vec3 specular_light, + inout float alpha) { //this makes lights behave closer to linear, but then addition of lights looks bad //better left disabled @@ -792,7 +1179,19 @@ LIGHT_SHADER_CODE float NdotL = dot(N, L); float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); + float cNdotV = max(abs(NdotV), 1e-6); + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + vec3 H = normalize(V + L); +#endif + +#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cNdotH = max(dot(N, H), 0.0); +#endif + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cLdotH = max(dot(L, H), 0.0); +#endif if (metallic < 1.0) { #if defined(DIFFUSE_OREN_NAYAR) @@ -828,13 +1227,9 @@ LIGHT_SHADER_CODE #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); + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; /* float energyBias = mix(roughness, 0.0, 0.5); @@ -868,20 +1263,18 @@ LIGHT_SHADER_CODE if (roughness > 0.0) { - // D - - float specular_brdf_NL; +#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); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); #elif defined(SPECULAR_PHONG) @@ -890,7 +1283,7 @@ LIGHT_SHADER_CODE 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); + phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); specular_brdf_NL = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); #elif defined(SPECULAR_TOON) @@ -903,38 +1296,32 @@ LIGHT_SHADER_CODE #elif defined(SPECULAR_DISABLED) // none.. - specular_brdf_NL = 0.0; #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_ggx = 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_ggx / aspect; + float ay = alpha_ggx * aspect; float XdotH = dot(T, H); float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); - float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + 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 alpha_ggx = roughness * roughness; + float D = D_GGX(cNdotH, alpha_ggx); + //float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); + float G = V_GGX(cNdotL, cNdotV, alpha_ggx); #endif // F - //float F0 = 1.0; - //float cLdotH5 = SchlickFresnel(cLdotH); - //float F = mix(cLdotH5, 1.0, F0); + 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; + specular_brdf_NL = cNdotL * D * F * G; #endif @@ -942,26 +1329,25 @@ LIGHT_SHADER_CODE 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); + 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 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 specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; - } + specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #endif } +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); +#endif + #endif //defined(USE_LIGHT_SHADER_CODE) } @@ -970,15 +1356,27 @@ LIGHT_SHADER_CODE #ifdef USE_SHADOW -#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, texture2D(p_shadow, p_pos).r) +#ifdef USE_RGBA_SHADOWS + +#define SHADOW_DEPTH(m_val) dot(m_val, vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) + +#else + +#define SHADOW_DEPTH(m_val) (m_val).r + +#endif + +#define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, SHADOW_DEPTH(texture2D(p_shadow, p_pos))) +#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, SHADOW_DEPTH(texture2DProj(p_shadow, p_pos))) -float sample_shadow( - highp sampler2D shadow, - highp vec2 pos, - highp float depth) { +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); @@ -997,6 +1395,10 @@ float sample_shadow( #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); @@ -1008,12 +1410,42 @@ float sample_shadow( #if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) - return SAMPLE_SHADOW_TEXEL(shadow, pos, depth); + 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 @@ -1022,6 +1454,7 @@ void main() { discard; #endif highp vec3 vertex = vertex_interp; + vec3 view = -normalize(vertex_interp); vec3 albedo = vec3(1.0); vec3 transmission = vec3(0.0); float metallic = 0.0; @@ -1034,10 +1467,19 @@ 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 + // gl_FragDepth is not available in GLES2, so writing to DEPTH is not converted to gl_FragDepth by Godot compiler resulting in a + // compile error because DEPTH is not a variable. + float m_DEPTH = 0.0; 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; @@ -1057,11 +1499,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 @@ -1077,8 +1519,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); @@ -1089,16 +1531,31 @@ FRAGMENT_SHADER_CODE vec3 diffuse_light = vec3(0.0, 0.0, 0.0); vec3 ambient_light = vec3(0.0, 0.0, 0.0); - vec3 eye_position = -normalize(vertex_interp); + vec3 eye_position = view; + +#if !defined(USE_SHADOW_TO_OPACITY) -#ifdef ALPHA_SCISSOR_USED +#if defined(ALPHA_SCISSOR_USED) if (alpha < alpha_scissor) { discard; } -#endif +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_DEPTH_PREPASS + if (alpha < 0.1) { + discard; + } +#endif // USE_DEPTH_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY #ifdef BASE_PASS //none + +#ifdef AMBIENT_LIGHT_DISABLED + ambient_light = vec3(0.0, 0.0, 0.0); +#else + #ifdef USE_RADIANCE_MAP vec3 ref_vec = reflect(-eye_position, N); @@ -1107,7 +1564,6 @@ FRAGMENT_SHADER_CODE 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; @@ -1118,11 +1574,131 @@ FRAGMENT_SHADER_CODE #else ambient_light = ambient_color.rgb; + specular_light = bg_color.rgb * bg_energy; #endif +#endif // AMBIENT_LIGHT_DISABLED 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) + + // environment BRDF approximation + + { + +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + + // scales the specular reflections, needs to be be computed before lighting happens, + // but after environment and reflection probes are added + //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 env = vec2(-1.04, 1.04) * a004 + r.zw; + + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; + +#endif + } + +#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, 0.0, 1.0), + vec3(0.866025, 0.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, 0.0, -1.0), + vec3(0.866025, 0.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 // @@ -1142,20 +1718,26 @@ FRAGMENT_SHADER_CODE 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.w); + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - light_att = vec3(omni_attenuation); + light_att = vec3(omni_attenuation); + } else { + light_att = vec3(0.0); + } L = normalize(light_vec); #endif +#if !defined(SHADOWS_DISABLED) + #ifdef USE_SHADOW { - highp vec3 splane = shadow_coord.xyz; - float shadow_len = length(splane); + highp vec4 splane = shadow_coord; + float shadow_len = length(splane.xyz); - splane = normalize(splane); + splane.xyz = normalize(splane.xyz); vec4 clamp_rect = light_clamp; @@ -1172,13 +1754,16 @@ FRAGMENT_SHADER_CODE splane.z = shadow_len / light_range; splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; - float shadow = sample_shadow(light_shadow_atlas, splane.xy, splane.z); + float shadow = sample_shadow(light_shadow_atlas, splane); - light_att *= shadow; + light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); } #endif +#endif //SHADOWS_DISABLED + #endif //type omni #ifdef LIGHT_MODE_DIRECTIONAL @@ -1189,7 +1774,124 @@ FRAGMENT_SHADER_CODE #endif float depth_z = -vertex.z; +#if !defined(SHADOWS_DISABLED) + #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 { + shadow_att = shadow2; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow3; + + pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#endif + } + } else { + if (depth_z < light_split_offsets.z) { + + 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 + + } else { + + 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 *= mix(shadow_color.rgb, vec3(1.0), 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 *= mix(shadow_color.rgb, vec3(1.0), shadow_att); + } + +#endif //LIGHT_USE_PSSM2 + +#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) + + light_att *= mix(shadow_color.rgb, vec3(1.0), sample_shadow(light_directional_shadow, shadow_coord)); +#endif //orthogonal + +#else //fragment version of pssm + { #ifdef LIGHT_USE_PSSM4 if (depth_z < light_split_offsets.w) { @@ -1199,34 +1901,31 @@ FRAGMENT_SHADER_CODE if (depth_z < light_split_offsets.x) { #endif //pssm2 - vec3 pssm_coord; + highp vec4 pssm_coord; float pssm_fade = 0.0; #ifdef LIGHT_USE_PSSM_BLEND float pssm_blend; - vec3 pssm_coord2; + 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 = shadow_coord; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord; #ifdef LIGHT_USE_PSSM_BLEND - splane = shadow_coord2; - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord2; pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif } else { - highp vec4 splane = shadow_coord2; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord2; #ifdef LIGHT_USE_PSSM_BLEND - splane = shadow_coord3; - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord3; pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); #endif @@ -1234,19 +1933,16 @@ FRAGMENT_SHADER_CODE } else { if (depth_z < light_split_offsets.z) { - highp vec4 splane = shadow_coord3; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord3; #if defined(LIGHT_USE_PSSM_BLEND) - splane = shadow_coord4; - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord4; pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); #endif } else { - highp vec4 splane = shadow_coord4; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord4; pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); #if defined(LIGHT_USE_PSSM_BLEND) @@ -1260,17 +1956,15 @@ FRAGMENT_SHADER_CODE #ifdef LIGHT_USE_PSSM2 if (depth_z < light_split_offsets.x) { - highp vec4 splane = shadow_coord; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord; #ifdef LIGHT_USE_PSSM_BLEND - splane = shadow_coord2; - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord2; pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif } else { - highp vec4 splane = shadow_coord2; - pssm_coord = splane.xyz / splane.w; + + 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; @@ -1281,24 +1975,27 @@ FRAGMENT_SHADER_CODE #if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) { - highp vec4 splane = shadow_coord; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord; } #endif - float shadow = sample_shadow(light_directional_shadow, pssm_coord.xy, pssm_coord.z); + float shadow = sample_shadow(light_directional_shadow, pssm_coord); #ifdef LIGHT_USE_PSSM_BLEND if (use_blend) { - shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2.xy, pssm_coord2.z), pssm_blend); + shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2), pssm_blend); } #endif - light_att *= shadow; + light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); } } +#endif //use vertex lighting + #endif //use shadow +#endif // SHADOWS_DISABLED + #endif #ifdef LIGHT_MODE_SPOT @@ -1311,40 +2008,62 @@ FRAGMENT_SHADER_CODE float light_length = length(light_rel_vec); float normalized_distance = light_length / light_range; - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; + if (normalized_distance < 1.0) { + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); + vec3 spot_dir = light_direction; - 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)); + float spot_cutoff = light_spot_angle; + float angle = dot(-normalize(light_rel_vec), spot_dir); - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + 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); + light_att = vec3(spot_attenuation); + } else { + light_att = vec3(0.0); + } + } else { + light_att = vec3(0.0); + } L = normalize(light_rel_vec); #endif +#if !defined(SHADOWS_DISABLED) + #ifdef USE_SHADOW { highp vec4 splane = shadow_coord; - splane.xyz /= splane.w; - float shadow = sample_shadow(light_shadow_atlas, splane.xy, splane.z); - light_att *= shadow; + float shadow = sample_shadow(light_shadow_atlas, splane); + light_att *= mix(shadow_color.rgb, vec3(1.0), shadow); } #endif -#endif +#endif // SHADOWS_DISABLED + +#endif // LIGHT_MODE_SPOT #ifdef USE_VERTEX_LIGHTING //vertex lighting - specular_light += specular_interp * specular * light_att; + specular_light += specular_interp * specular_blob_intensity * light_att; diffuse_light += diffuse_interp * albedo * light_att; + // Same as above, needed for VERTEX_LIGHTING or else lights are too bright + 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 env = vec2(-1.04, 1.04) * a004 + r.zw; + + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; + #else //fragment lighting light_compute( @@ -1357,22 +2076,42 @@ FRAGMENT_SHADER_CODE light_att, albedo, transmission, - specular * light_specular, + specular_blob_intensity * light_specular, roughness, metallic, + specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, - specular_light); + specular_light, + alpha); #endif //vertex lighting #endif //USE_LIGHTING //compute and merge +#ifdef USE_SHADOW_TO_OPACITY + + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_DEPTH_PREPASS + if (alpha < 0.1) { + discard; + } +#endif // USE_DEPTH_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY + #ifndef RENDER_DEPTH #ifdef SHADELESS @@ -1392,25 +2131,79 @@ FRAGMENT_SHADER_CODE diffuse_light *= 1.0 - metallic; ambient_light *= 1.0 - metallic; - // environment BRDF approximation + 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); + +//apply fog +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#if defined(USE_VERTEX_LIGHTING) + +#if defined(BASE_PASS) + gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_interp.rgb, fog_interp.a); +#else + gl_FragColor.rgb *= (1.0 - fog_interp.a); +#endif // BASE_PASS + +#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 + vec3 fog_color = fog_color_base.rgb; +#endif + +#ifdef FOG_DEPTH_ENABLED - // TODO shadeless { - 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; - vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo); - specular_light *= AB.x * specular_color + AB.y; + float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); + + fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; + + 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 - gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); - // gl_FragColor = vec4(normal, 1.0); +#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 + +#if defined(BASE_PASS) + gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_color, fog_amount); +#else + gl_FragColor.rgb *= (1.0 - fog_amount); +#endif // BASE_PASS + +#endif //use vertex lit + +#endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) #endif //unshaded -#endif // not RENDER_DEPTH +#else // not RENDER_DEPTH +//depth render +#ifdef USE_RGBA_SHADOWS + + highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias + highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); + comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); + gl_FragColor = comp; + +#endif +#endif } diff --git a/drivers/gles2/shaders/stdlib.glsl b/drivers/gles2/shaders/stdlib.glsl index 6bc81a22d8..9c74418743 100644 --- a/drivers/gles2/shaders/stdlib.glsl +++ b/drivers/gles2/shaders/stdlib.glsl @@ -35,3 +35,386 @@ highp vec4 texel2DFetch(highp sampler2D tex, ivec2 size, ivec2 coord) { return texture2DLod(tex, vec2(x_coord, y_coord), 0.0); } + +#if defined(SINH_USED) + +highp float sinh(highp float x) { + return 0.5 * (exp(x) - exp(-x)); +} + +highp vec2 sinh(highp vec2 x) { + return 0.5 * vec2(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y)); +} + +highp vec3 sinh(highp vec3 x) { + return 0.5 * vec3(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y), exp(x.z) - exp(-x.z)); +} + +highp vec4 sinh(highp vec4 x) { + return 0.5 * vec4(exp(x.x) - exp(-x.x), exp(x.y) - exp(-x.y), exp(x.z) - exp(-x.z), exp(x.w) - exp(-x.w)); +} + +#endif + +#if defined(COSH_USED) + +highp float cosh(highp float x) { + return 0.5 * (exp(x) + exp(-x)); +} + +highp vec2 cosh(highp vec2 x) { + return 0.5 * vec2(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y)); +} + +highp vec3 cosh(highp vec3 x) { + return 0.5 * vec3(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y), exp(x.z) + exp(-x.z)); +} + +highp vec4 cosh(highp vec4 x) { + return 0.5 * vec4(exp(x.x) + exp(-x.x), exp(x.y) + exp(-x.y), exp(x.z) + exp(-x.z), exp(x.w) + exp(-x.w)); +} + +#endif + +#if defined(TANH_USED) + +highp float tanh(highp float x) { + highp float exp2x = exp(2.0 * x); + return (exp2x - 1.0) / (exp2x + 1.0); +} + +highp vec2 tanh(highp vec2 x) { + highp float exp2x = exp(2.0 * x.x); + highp float exp2y = exp(2.0 * x.y); + return vec2((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0)); +} + +highp vec3 tanh(highp vec3 x) { + highp float exp2x = exp(2.0 * x.x); + highp float exp2y = exp(2.0 * x.y); + highp float exp2z = exp(2.0 * x.z); + return vec3((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0), (exp2z - 1.0) / (exp2z + 1.0)); +} + +highp vec4 tanh(highp vec4 x) { + highp float exp2x = exp(2.0 * x.x); + highp float exp2y = exp(2.0 * x.y); + highp float exp2z = exp(2.0 * x.z); + highp float exp2w = exp(2.0 * x.w); + return vec4((exp2x - 1.0) / (exp2x + 1.0), (exp2y - 1.0) / (exp2y + 1.0), (exp2z - 1.0) / (exp2z + 1.0), (exp2w - 1.0) / (exp2w + 1.0)); +} + +#endif + +#if defined(ASINH_USED) + +highp float asinh(highp float x) { + return sign(x) * log(abs(x) + sqrt(1.0 + x * x)); +} + +highp vec2 asinh(highp vec2 x) { + return vec2(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y))); +} + +highp vec3 asinh(highp vec3 x) { + return vec3(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y)), sign(x.z) * log(abs(x.z) + sqrt(1.0 + x.z * x.z))); +} + +highp vec4 asinh(highp vec4 x) { + return vec4(sign(x.x) * log(abs(x.x) + sqrt(1.0 + x.x * x.x)), sign(x.y) * log(abs(x.y) + sqrt(1.0 + x.y * x.y)), sign(x.z) * log(abs(x.z) + sqrt(1.0 + x.z * x.z)), sign(x.w) * log(abs(x.w) + sqrt(1.0 + x.w * x.w))); +} + +#endif + +#if defined(ACOSH_USED) + +highp float acosh(highp float x) { + return log(x + sqrt(x * x - 1.0)); +} + +highp vec2 acosh(highp vec2 x) { + return vec2(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0))); +} + +highp vec3 acosh(highp vec3 x) { + return vec3(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0)), log(x.z + sqrt(x.z * x.z - 1.0))); +} + +highp vec4 acosh(highp vec4 x) { + return vec4(log(x.x + sqrt(x.x * x.x - 1.0)), log(x.y + sqrt(x.y * x.y - 1.0)), log(x.z + sqrt(x.z * x.z - 1.0)), log(x.w + sqrt(x.w * x.w - 1.0))); +} + +#endif + +#if defined(ATANH_USED) + +highp float atanh(highp float x) { + return 0.5 * log((1.0 + x) / (1.0 - x)); +} + +highp vec2 atanh(highp vec2 x) { + return 0.5 * vec2(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y))); +} + +highp vec3 atanh(highp vec3 x) { + return 0.5 * vec3(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y)), log((1.0 + x.z) / (1.0 - x.z))); +} + +highp vec4 atanh(highp vec4 x) { + return 0.5 * vec4(log((1.0 + x.x) / (1.0 - x.x)), log((1.0 + x.y) / (1.0 - x.y)), log((1.0 + x.z) / (1.0 - x.z)), log((1.0 + x.w) / (1.0 - x.w))); +} + +#endif + +#if defined(ROUND_USED) + +highp float round(highp float x) { + return floor(x + 0.5); +} + +highp vec2 round(highp vec2 x) { + return floor(x + vec2(0.5)); +} + +highp vec3 round(highp vec3 x) { + return floor(x + vec3(0.5)); +} + +highp vec4 round(highp vec4 x) { + return floor(x + vec4(0.5)); +} + +#endif + +#if defined(ROUND_EVEN_USED) + +highp float roundEven(highp float x) { + highp float t = x + 0.5; + highp float f = floor(t); + highp float r; + if (t == f) { + if (x > 0) + r = f - mod(f, 2); + else + r = f + mod(f, 2); + } else + r = f; + return r; +} + +highp vec2 roundEven(highp vec2 x) { + return vec2(roundEven(x.x), roundEven(x.y)); +} + +highp vec3 roundEven(highp vec3 x) { + return vec3(roundEven(x.x), roundEven(x.y), roundEven(x.z)); +} + +highp vec4 roundEven(highp vec4 x) { + return vec4(roundEven(x.x), roundEven(x.y), roundEven(x.z), roundEven(x.w)); +} + +#endif + +#if defined(IS_INF_USED) + +bool isinf(highp float x) { + return (2 * x == x) && (x != 0); +} + +bvec2 isinf(highp vec2 x) { + return bvec2((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0)); +} + +bvec3 isinf(highp vec3 x) { + return bvec3((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0), (2 * x.z == x.z) && (x.z != 0)); +} + +bvec4 isinf(highp vec4 x) { + return bvec4((2 * x.x == x.x) && (x.x != 0), (2 * x.y == x.y) && (x.y != 0), (2 * x.z == x.z) && (x.z != 0), (2 * x.w == x.w) && (x.w != 0)); +} + +#endif + +#if defined(IS_NAN_USED) + +bool isnan(highp float x) { + return x != x; +} + +bvec2 isnan(highp vec2 x) { + return bvec2(x.x != x.x, x.y != x.y); +} + +bvec3 isnan(highp vec3 x) { + return bvec3(x.x != x.x, x.y != x.y, x.z != x.z); +} + +bvec4 isnan(highp vec4 x) { + return bvec4(x.x != x.x, x.y != x.y, x.z != x.z, x.w != x.w); +} + +#endif + +#if defined(TRUNC_USED) + +highp float trunc(highp float x) { + return x < 0 ? -floor(-x) : floor(x); +} + +highp vec2 trunc(highp vec2 x) { + return vec2(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y)); +} + +highp vec3 trunc(highp vec3 x) { + return vec3(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y), x.z < 0 ? -floor(-x.z) : floor(x.z)); +} + +highp vec4 trunc(highp vec4 x) { + return vec4(x.x < 0 ? -floor(-x.x) : floor(x.x), x.y < 0 ? -floor(-x.y) : floor(x.y), x.z < 0 ? -floor(-x.z) : floor(x.z), x.w < 0 ? -floor(-x.w) : floor(x.w)); +} + +#endif + +#if defined(DETERMINANT_USED) + +highp float determinant(highp mat2 m) { + return m[0].x * m[1].y - m[1].x * m[0].y; +} + +highp float determinant(highp mat3 m) { + return m[0].x * (m[1].y * m[2].z - m[2].y * m[1].z) - m[1].x * (m[0].y * m[2].z - m[2].y * m[0].z) + m[2].x * (m[0].y * m[1].z - m[1].y * m[0].z); +} + +highp float determinant(highp mat4 m) { + highp float s00 = m[2].z * m[3].w - m[3].z * m[2].w; + highp float s01 = m[2].y * m[3].w - m[3].y * m[2].w; + highp float s02 = m[2].y * m[3].z - m[3].y * m[2].z; + highp float s03 = m[2].x * m[3].w - m[3].x * m[2].w; + highp float s04 = m[2].x * m[3].z - m[3].x * m[2].z; + highp float s05 = m[2].x * m[3].y - m[3].x * m[2].y; + highp vec4 c = vec4((m[1].y * s00 - m[1].z * s01 + m[1].w * s02), -(m[1].x * s00 - m[1].z * s03 + m[1].w * s04), (m[1].x * s01 - m[1].y * s03 + m[1].w * s05), -(m[1].x * s02 - m[1].y * s04 + m[1].z * s05)); + return m[0].x * c.x + m[0].y * c.y + m[0].z * c.z + m[0].w * c.w; +} + +#endif + +#if defined(INVERSE_USED) + +highp mat2 inverse(highp mat2 m) { + highp float d = 1.0 / (m[0].x * m[1].y - m[1].x * m[0].y); + return mat2( + vec2(m[1].y * d, -m[0].y * d), + vec2(-m[1].x * d, m[0].x * d)); +} + +highp mat3 inverse(highp mat3 m) { + highp float d = 1.0 / (m[0].x * (m[1].y * m[2].z - m[2].y * m[1].z) - m[1].x * (m[0].y * m[2].z - m[2].y * m[0].z) + m[2].x * (m[0].y * m[1].z - m[1].y * m[0].z)); + return mat3( + vec3((m[1].y * m[2].z - m[2].y * m[1].z), -(m[1].x * m[2].z - m[2].x * m[1].z), (m[1].x * m[2].y - m[2].x * m[1].y)) * d, + vec3(-(m[0].y * m[2].z - m[2].y * m[0].z), (m[0].x * m[2].z - m[2].x * m[0].z), -(m[0].x * m[2].y - m[2].x * m[0].y)) * d, + vec3((m[0].y * m[1].z - m[1].y * m[0].z), -(m[0].x * m[1].z - m[1].x * m[0].z), (m[0].x * m[1].y - m[1].x * m[0].y)) * d); +} + +highp mat4 inverse(highp mat4 m) { + highp float c00 = m[2].z * m[3].w - m[3].z * m[2].w; + highp float c02 = m[1].z * m[3].w - m[3].z * m[1].w; + highp float c03 = m[1].z * m[2].w - m[2].z * m[1].w; + + highp float c04 = m[2].y * m[3].w - m[3].y * m[2].w; + highp float c06 = m[1].y * m[3].w - m[3].y * m[1].w; + highp float c07 = m[1].y * m[2].w - m[2].y * m[1].w; + + highp float c08 = m[2].y * m[3].z - m[3].y * m[2].z; + highp float c10 = m[1].y * m[3].z - m[3].y * m[1].z; + highp float c11 = m[1].y * m[2].z - m[2].y * m[1].z; + + highp float c12 = m[2].x * m[3].w - m[3].x * m[2].w; + highp float c14 = m[1].x * m[3].w - m[3].x * m[1].w; + highp float c15 = m[1].x * m[2].w - m[2].x * m[1].w; + + highp float c16 = m[2].x * m[3].z - m[3].x * m[2].z; + highp float c18 = m[1].x * m[3].z - m[3].x * m[1].z; + highp float c19 = m[1].x * m[2].z - m[2].x * m[1].z; + + highp float c20 = m[2].x * m[3].y - m[3].x * m[2].y; + highp float c22 = m[1].x * m[3].y - m[3].x * m[1].y; + highp float c23 = m[1].x * m[2].y - m[2].x * m[1].y; + + vec4 f0 = vec4(c00, c00, c02, c03); + vec4 f1 = vec4(c04, c04, c06, c07); + vec4 f2 = vec4(c08, c08, c10, c11); + vec4 f3 = vec4(c12, c12, c14, c15); + vec4 f4 = vec4(c16, c16, c18, c19); + vec4 f5 = vec4(c20, c20, c22, c23); + + vec4 v0 = vec4(m[1].x, m[0].x, m[0].x, m[0].x); + vec4 v1 = vec4(m[1].y, m[0].y, m[0].y, m[0].y); + vec4 v2 = vec4(m[1].z, m[0].z, m[0].z, m[0].z); + vec4 v3 = vec4(m[1].w, m[0].w, m[0].w, m[0].w); + + vec4 inv0 = vec4(v1 * f0 - v2 * f1 + v3 * f2); + vec4 inv1 = vec4(v0 * f0 - v2 * f3 + v3 * f4); + vec4 inv2 = vec4(v0 * f1 - v1 * f3 + v3 * f5); + vec4 inv3 = vec4(v0 * f2 - v1 * f4 + v2 * f5); + + vec4 sa = vec4(+1, -1, +1, -1); + vec4 sb = vec4(-1, +1, -1, +1); + + mat4 inv = mat4(inv0 * sa, inv1 * sb, inv2 * sa, inv3 * sb); + + vec4 r0 = vec4(inv[0].x, inv[1].x, inv[2].x, inv[3].x); + vec4 d0 = vec4(m[0] * r0); + + highp float d1 = (d0.x + d0.y) + (d0.z + d0.w); + highp float d = 1.0 / d1; + + return inv * d; +} + +#endif + +#ifndef USE_GLES_OVER_GL + +#if defined(TRANSPOSE_USED) + +highp mat2 transpose(highp mat2 m) { + return mat2( + vec2(m[0].x, m[1].x), + vec2(m[0].y, m[1].y)); +} + +highp mat3 transpose(highp mat3 m) { + return mat3( + vec3(m[0].x, m[1].x, m[2].x), + vec3(m[0].y, m[1].y, m[2].y), + vec3(m[0].z, m[1].z, m[2].z)); +} + +#endif + +highp mat4 transpose(highp mat4 m) { + return mat4( + vec4(m[0].x, m[1].x, m[2].x, m[3].x), + vec4(m[0].y, m[1].y, m[2].y, m[3].y), + vec4(m[0].z, m[1].z, m[2].z, m[3].z), + vec4(m[0].w, m[1].w, m[2].w, m[3].w)); +} + +#if defined(OUTER_PRODUCT_USED) + +highp mat2 outerProduct(highp vec2 c, highp vec2 r) { + return mat2(c * r.x, c * r.y); +} + +highp mat3 outerProduct(highp vec3 c, highp vec3 r) { + return mat3(c * r.x, c * r.y, c * r.z); +} + +highp mat4 outerProduct(highp vec4 c, highp vec4 r) { + return mat4(c * r.x, c * r.y, c * r.z, c * r.w); +} + +#endif + +#endif diff --git a/drivers/gles2/shaders/tonemap.glsl b/drivers/gles2/shaders/tonemap.glsl index eae3b5a1ca..585d821626 100644 --- a/drivers/gles2/shaders/tonemap.glsl +++ b/drivers/gles2/shaders/tonemap.glsl @@ -1,66 +1,103 @@ /* clang-format off */ [vertex] -layout(location = 0) in highp vec4 vertex_attrib; +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +precision highp float; +precision highp int; +#endif + +attribute vec2 vertex_attrib; // attrib:0 /* clang-format on */ -layout(location = 4) in vec2 uv_in; +attribute vec2 uv_in; // attrib:4 -out vec2 uv_interp; +varying vec2 uv_interp; void main() { + gl_Position = vec4(vertex_attrib, 0.0, 1.0); - gl_Position = vertex_attrib; uv_interp = uv_in; -#ifdef V_FLIP - uv_interp.y = 1.0 - uv_interp.y; -#endif } /* clang-format off */ [fragment] -#if !defined(GLES_OVER_GL) -precision mediump float; + +// texture2DLodEXT and textureCubeLodEXT are fragment shader specific. +// Do not copy these defines in the vertex section. +#ifndef USE_GLES_OVER_GL +#ifdef GL_EXT_shader_texture_lod +#extension GL_EXT_shader_texture_lod : enable +#define texture2DLod(img, coord, lod) texture2DLodEXT(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCubeLodEXT(img, coord, lod) #endif +#endif // !USE_GLES_OVER_GL -in vec2 uv_interp; -/* clang-format on */ +#ifdef GL_ARB_shader_texture_lod +#extension GL_ARB_shader_texture_lod : enable +#endif -uniform highp sampler2D source; //texunit:0 +#if !defined(GL_EXT_shader_texture_lod) && !defined(GL_ARB_shader_texture_lod) +#define texture2DLod(img, coord, lod) texture2D(img, coord, lod) +#define textureCubeLod(img, coord, lod) textureCube(img, coord, lod) +#endif -uniform float exposure; -uniform float white; +// Allows the use of bitshift operators for bicubic upscale +#ifdef GL_EXT_gpu_shader4 +#extension GL_EXT_gpu_shader4 : enable +#endif -#ifdef USE_AUTO_EXPOSURE +#ifdef USE_GLES_OVER_GL +#define lowp +#define mediump +#define highp +#else +#if defined(USE_HIGHP_PRECISION) +precision highp float; +precision highp int; +#else +precision mediump float; +precision mediump int; +#endif +#endif -uniform highp sampler2D source_auto_exposure; //texunit:1 -uniform highp float auto_exposure_grey; +#include "stdlib.glsl" -#endif +varying vec2 uv_interp; +/* clang-format on */ -#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) +uniform highp sampler2D source; //texunit:0 -uniform highp sampler2D source_glow; //texunit:2 +#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) +#define USING_GLOW // only use glow when at least one glow level is selected + +#ifdef USE_MULTI_TEXTURE_GLOW +uniform highp sampler2D source_glow1; //texunit:1 +uniform highp sampler2D source_glow2; //texunit:2 +uniform highp sampler2D source_glow3; //texunit:3 +uniform highp sampler2D source_glow4; //texunit:4 +uniform highp sampler2D source_glow5; //texunit:5 +uniform highp sampler2D source_glow6; //texunit:6 +uniform highp sampler2D source_glow7; //texunit:7 +#else +uniform highp sampler2D source_glow; //texunit:1 +#endif uniform highp float glow_intensity; - #endif #ifdef USE_BCS - uniform vec3 bcs; - #endif #ifdef USE_COLOR_CORRECTION - -uniform sampler2D color_correction; //texunit:3 - +uniform sampler2D color_correction; //texunit:2 #endif -layout(location = 0) out vec4 frag_color; - +#ifdef GL_EXT_gpu_shader4 #ifdef USE_GLOW_FILTER_BICUBIC - // w0, w1, w2, and w3 are the four cubic B-spline basis functions float w0(float a) { return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0); @@ -101,8 +138,10 @@ uniform ivec2 glow_texture_size; vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { float lod = float(p_lod); vec2 tex_size = vec2(glow_texture_size >> p_lod); - vec2 pixel_size = 1.0 / tex_size; - uv = uv * tex_size + 0.5; + vec2 pixel_size = vec2(1.0) / tex_size; + + uv = uv * tex_size + vec2(0.5); + vec2 iuv = floor(uv); vec2 fuv = fract(uv); @@ -113,73 +152,97 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { float h0y = h0(fuv.y); float h1y = h1(fuv.y); - vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - 0.5) * pixel_size; - vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - 0.5) * pixel_size; - vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - 0.5) * pixel_size; - vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - 0.5) * pixel_size; + vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5)) * pixel_size; + vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5)) * pixel_size; + vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5)) * pixel_size; + vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5)) * pixel_size; - return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) + - (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod))); + return (g0(fuv.y) * (g0x * texture2DLod(tex, p0, lod) + g1x * texture2DLod(tex, p1, lod))) + + (g1(fuv.y) * (g0x * texture2DLod(tex, p2, lod) + g1x * texture2DLod(tex, p3, lod))); } #define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod) +#else //!USE_GLOW_FILTER_BICUBIC +#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2DLod(m_tex, m_uv, float(m_lod)) +#endif //USE_GLOW_FILTER_BICUBIC -#else +#else //!GL_EXT_gpu_shader4 +#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2DLod(m_tex, m_uv, float(m_lod)) +#endif //GL_EXT_gpu_shader4 -#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod)) +vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode +#ifdef USE_GLOW_REPLACE + color = glow; +#endif +#ifdef USE_GLOW_SCREEN + color = max((color + glow) - (color * glow), vec3(0.0)); #endif -vec3 tonemap_filmic(vec3 color, float white) { +#ifdef USE_GLOW_SOFTLIGHT + glow = glow * vec3(0.5) + vec3(0.5); - float A = 0.15; - float B = 0.50; - float C = 0.10; - float D = 0.20; - float E = 0.02; - float F = 0.30; - float W = 11.2; + color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); + color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); + color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); +#endif - vec3 coltn = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; - float whitetn = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F; +#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) // no other selected -> additive + color += glow; +#endif - return coltn / whitetn; + return color; } -vec3 tonemap_aces(vec3 color) { - float a = 2.51f; - float b = 0.03f; - float c = 2.43f; - float d = 0.59f; - float e = 0.14f; - return color = clamp((color * (a * color + b)) / (color * (c * color + d) + e), vec3(0.0), vec3(1.0)); +vec3 apply_bcs(vec3 color, vec3 bcs) { + color = mix(vec3(0.0), color, bcs.x); + color = mix(vec3(0.5), color, bcs.y); + color = mix(vec3(dot(vec3(1.0), color) * 0.33333), color, bcs.z); + + return color; } -vec3 tonemap_reindhart(vec3 color, float white) { +vec3 apply_color_correction(vec3 color, sampler2D correction_tex) { + color.r = texture2D(correction_tex, vec2(color.r, 0.0)).r; + color.g = texture2D(correction_tex, vec2(color.g, 0.0)).g; + color.b = texture2D(correction_tex, vec2(color.b, 0.0)).b; - return (color * (1.0 + (color / (white)))) / (1.0 + color); + return color; } void main() { + vec3 color = texture2DLod(source, uv_interp, 0.0).rgb; - vec4 color = textureLod(source, uv_interp, 0.0); + // Glow -#ifdef USE_AUTO_EXPOSURE - - color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / auto_exposure_grey; +#ifdef USING_GLOW + vec3 glow = vec3(0.0); +#ifdef USE_MULTI_TEXTURE_GLOW +#ifdef USE_GLOW_LEVEL1 + glow += GLOW_TEXTURE_SAMPLE(source_glow1, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL2 + glow += GLOW_TEXTURE_SAMPLE(source_glow2, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL3 + glow += GLOW_TEXTURE_SAMPLE(source_glow3, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL4 + glow += GLOW_TEXTURE_SAMPLE(source_glow4, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL5 + glow += GLOW_TEXTURE_SAMPLE(source_glow5, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL6 + glow += GLOW_TEXTURE_SAMPLE(source_glow6, uv_interp, 0).rgb; +#ifdef USE_GLOW_LEVEL7 + glow += GLOW_TEXTURE_SAMPLE(source_glow7, uv_interp, 0).rgb; +#endif +#endif +#endif +#endif +#endif #endif - - color *= exposure; - -#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7) -#define USING_GLOW #endif -#if defined(USING_GLOW) - vec3 glow = vec3(0.0); +#else #ifdef USE_GLOW_LEVEL1 - glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 1).rgb; #endif @@ -206,100 +269,21 @@ void main() { #ifdef USE_GLOW_LEVEL7 glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 7).rgb; #endif +#endif //USE_MULTI_TEXTURE_GLOW glow *= glow_intensity; - -#endif - -#ifdef USE_REINDHART_TONEMAPPER - - color.rgb = tonemap_reindhart(color.rgb, white); - -#if defined(USING_GLOW) - glow = tonemap_reindhart(glow, white); -#endif - + color = apply_glow(color, glow); #endif -#ifdef USE_FILMIC_TONEMAPPER - - color.rgb = tonemap_filmic(color.rgb, white); - -#if defined(USING_GLOW) - glow = tonemap_filmic(glow, white); -#endif - -#endif - -#ifdef USE_ACES_TONEMAPPER - - color.rgb = tonemap_aces(color.rgb); - -#if defined(USING_GLOW) - glow = tonemap_aces(glow); -#endif - -#endif - - //regular Linear -> SRGB conversion - vec3 a = vec3(0.055); - color.rgb = mix((vec3(1.0) + a) * pow(color.rgb, vec3(1.0 / 2.4)) - a, 12.92 * color.rgb, lessThan(color.rgb, vec3(0.0031308))); - -#if defined(USING_GLOW) - glow = mix((vec3(1.0) + a) * pow(glow, vec3(1.0 / 2.4)) - a, 12.92 * glow, lessThan(glow, vec3(0.0031308))); -#endif - - //glow needs to be added in SRGB space (together with image space effects) - - color.rgb = clamp(color.rgb, 0.0, 1.0); - -#if defined(USING_GLOW) - glow = clamp(glow, 0.0, 1.0); -#endif - -#ifdef USE_GLOW_REPLACE - - color.rgb = glow; - -#endif - -#ifdef USE_GLOW_SCREEN - - color.rgb = max((color.rgb + glow) - (color.rgb * glow), vec3(0.0)); - -#endif - -#ifdef USE_GLOW_SOFTLIGHT - - { - - glow = (glow * 0.5) + 0.5; - color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r))); - color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g))); - color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b))); - } - -#endif - -#if defined(USING_GLOW) && !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) - //additive - color.rgb += glow; -#endif + // Additional effects #ifdef USE_BCS - - color.rgb = mix(vec3(0.0), color.rgb, bcs.x); - color.rgb = mix(vec3(0.5), color.rgb, bcs.y); - color.rgb = mix(vec3(dot(vec3(1.0), color.rgb) * 0.33333), color.rgb, bcs.z); - + color = apply_bcs(color, bcs); #endif #ifdef USE_COLOR_CORRECTION - - color.r = texture(color_correction, vec2(color.r, 0.0)).r; - color.g = texture(color_correction, vec2(color.g, 0.0)).g; - color.b = texture(color_correction, vec2(color.b, 0.0)).b; + color = apply_color_correction(color, color_correction); #endif - frag_color = vec4(color.rgb, 1.0); + gl_FragColor = vec4(color, 1.0); } diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c9bdc6f5c3..edffe852a2 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -146,10 +146,15 @@ void RasterizerCanvasGLES3::canvas_begin() { if (storage->frame.current_rt && storage->frame.clear_request) { // a clear request may be pending, so do it + bool transparent = storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; - glClearColor(storage->frame.clear_request_color.r, storage->frame.clear_request_color.g, storage->frame.clear_request_color.b, storage->frame.clear_request_color.a); + glClearColor(storage->frame.clear_request_color.r, + storage->frame.clear_request_color.g, + storage->frame.clear_request_color.b, + transparent ? storage->frame.clear_request_color.a : 1.0); glClear(GL_COLOR_BUFFER_BIT); storage->frame.clear_request = false; + glColorMask(1, 1, 1, transparent ? 1 : 0); } reset_canvas(); @@ -158,7 +163,10 @@ void RasterizerCanvasGLES3::canvas_begin() { state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_NINEPATCH, false); @@ -190,6 +198,9 @@ void RasterizerCanvasGLES3::canvas_end() { glBindVertexArray(0); glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0); + glColorMask(1, 1, 1, 1); + + glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); state.using_texture_rect = false; state.using_ninepatch = false; @@ -259,6 +270,7 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasGLES3::_bind_canvas_texture(con } normal_map = normal_map->get_ptr(); + glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); state.current_normal = p_normal_map; @@ -317,12 +329,9 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun uint32_t buffer_ofs = 0; //vertex -#ifdef DEBUG_ENABLED - ERR_FAIL_COND(buffer_ofs > data.polygon_buffer_size); -#endif glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Vector2) * p_vertex_count; //color #ifdef DEBUG_ENABLED @@ -340,7 +349,7 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Color) * p_vertex_count; } @@ -352,7 +361,7 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Vector2) * p_vertex_count; } else { @@ -368,12 +377,12 @@ void RasterizerCanvasGLES3::_draw_polygon(const int *p_indices, int p_index_coun glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(int) * 4 * p_vertex_count, p_bones); glEnableVertexAttribArray(VS::ARRAY_BONES); //glVertexAttribPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, false, sizeof(int) * 4, ((uint8_t *)0) + buffer_ofs); - glVertexAttribIPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, sizeof(int) * 4, ((uint8_t *)0) + buffer_ofs); + glVertexAttribIPointer(VS::ARRAY_BONES, 4, GL_UNSIGNED_INT, sizeof(int) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(int) * 4 * p_vertex_count; glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(float) * 4 * p_vertex_count, p_weights); glEnableVertexAttribArray(VS::ARRAY_WEIGHTS); - glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, false, sizeof(float) * 4, ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_WEIGHTS, 4, GL_FLOAT, false, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(float) * 4 * p_vertex_count; } else if (state.using_skeleton) { @@ -413,7 +422,7 @@ void RasterizerCanvasGLES3::_draw_generic(GLuint p_primitive, int p_vertex_count //vertex glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_vertices); glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Vector2) * p_vertex_count; //color @@ -428,7 +437,7 @@ void RasterizerCanvasGLES3::_draw_generic(GLuint p_primitive, int p_vertex_count glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Color) * p_vertex_count, p_colors); glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Color) * p_vertex_count; } @@ -436,7 +445,7 @@ void RasterizerCanvasGLES3::_draw_generic(GLuint p_primitive, int p_vertex_count glBufferSubData(GL_ARRAY_BUFFER, buffer_ofs, sizeof(Vector2) * p_vertex_count, p_uvs); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)0) + buffer_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buffer_ofs)); buffer_ofs += sizeof(Vector2) * p_vertex_count; } else { @@ -571,10 +580,10 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur #ifdef GLES_OVER_GL if (line->antialiased) { glEnable(GL_LINE_SMOOTH); - for (int i = 0; i < 4; i++) { + for (int j = 0; j < 4; j++) { Vector2 vertsl[2] = { - verts[i], - verts[(i + 1) % 4], + verts[j], + verts[(j + 1) % 4], }; _draw_gui_primitive(2, vertsl, NULL, NULL); } @@ -684,7 +693,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(dst_rect.position.x, dst_rect.position.y, dst_rect.size.x, dst_rect.size.y)); state.canvas_shader.set_uniform(CanvasShaderGLES3::SRC_RECT, Color(src_rect.position.x, src_rect.position.y, src_rect.size.x, src_rect.size.y)); - state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, (rect->flags & CANVAS_RECT_CLIP_UV) ? true : false); + state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, rect->flags & CANVAS_RECT_CLIP_UV); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -772,8 +781,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } if (primitive->colors.size() == 1 && primitive->points.size() > 1) { - Color c = primitive->colors[0]; - glVertexAttrib4f(VS::ARRAY_COLOR, c.r, c.g, c.b, c.a); + Color col = primitive->colors[0]; + glVertexAttrib4f(VS::ARRAY_COLOR, col.r, col.g, col.b, col.a); } else if (primitive->colors.empty()) { glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); @@ -816,6 +825,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); } + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * mesh->transform); + RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(mesh->mesh); if (mesh_data) { @@ -824,6 +835,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing glBindVertexArray(s->array_id); + glVertexAttrib4f(VS::ARRAY_COLOR, mesh->modulate.r, mesh->modulate.g, mesh->modulate.b, mesh->modulate.a); + if (s->index_array_len) { glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0); } else { @@ -833,6 +846,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur glBindVertexArray(0); } } + state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); + } break; case Item::Command::TYPE_MULTIMESH: { @@ -861,7 +876,11 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); } - 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; + } for (int j = 0; j < mesh_data->surfaces.size(); j++) { RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j]; @@ -872,17 +891,17 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4; glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(0)); glVertexAttribDivisor(8, 1); glEnableVertexAttribArray(9); - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 4 * 4); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4)); glVertexAttribDivisor(9, 1); int color_ofs; if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) { glEnableVertexAttribArray(10); - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 8 * 4); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4)); glVertexAttribDivisor(10, 1); color_ofs = 12 * 4; } else { @@ -901,14 +920,14 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } break; case VS::MULTIMESH_COLOR_8BIT: { glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, ((uint8_t *)NULL) + color_ofs); + glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); glVertexAttribDivisor(11, 1); custom_data_ofs += 4; } break; case VS::MULTIMESH_COLOR_FLOAT: { glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + color_ofs); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); glVertexAttribDivisor(11, 1); custom_data_ofs += 4 * 4; } break; @@ -922,13 +941,13 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } break; case VS::MULTIMESH_CUSTOM_DATA_8BIT: { glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, ((uint8_t *)NULL) + custom_data_ofs); + glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); glVertexAttribDivisor(12, 1); } break; case VS::MULTIMESH_CUSTOM_DATA_FLOAT: { glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + custom_data_ofs); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); glVertexAttribDivisor(12, 1); } break; } @@ -976,7 +995,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map); if (texture) { - Size2 texpixel_size(1.0 / (texture->width / particles_cmd->h_frames), 1.0 / (texture->height / particles_cmd->v_frames)); + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); } else { state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0)); @@ -993,9 +1012,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf); } - state.canvas_shader.set_uniform(CanvasShaderGLES3::H_FRAMES, particles_cmd->h_frames); - state.canvas_shader.set_uniform(CanvasShaderGLES3::V_FRAMES, particles_cmd->v_frames); - glBindVertexArray(data.particle_quad_array); //use particle quad array glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer @@ -1006,43 +1022,41 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur if (particles->draw_order != VS::PARTICLES_DRAW_ORDER_LIFETIME) { glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 3); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); glVertexAttribDivisor(9, 1); glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); glVertexAttribDivisor(10, 1); glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); glVertexAttribDivisor(11, 1); glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 2); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); glVertexAttribDivisor(12, 1); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount); } else { //split - - int stride = sizeof(float) * 4 * 6; int split = int(Math::ceil(particles->phase * particles->amount)); if (amount - split > 0) { glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 3); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 4); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4)); glVertexAttribDivisor(9, 1); glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 5); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5)); glVertexAttribDivisor(10, 1); glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + 0); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0)); glVertexAttribDivisor(11, 1); glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 2); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2)); glVertexAttribDivisor(12, 1); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, amount - split); @@ -1050,19 +1064,19 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur if (split > 0) { glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 3); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); glVertexAttribDivisor(9, 1); glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); glVertexAttribDivisor(10, 1); glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); glVertexAttribDivisor(11, 1); glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 2); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); glVertexAttribDivisor(12, 1); glDrawArraysInstanced(GL_TRIANGLE_FAN, 0, 4, split); @@ -1072,8 +1086,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur glBindVertexArray(0); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); state.using_texture_rect = true; _set_texture_rect_mode(false); @@ -1088,12 +1102,12 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur points[numpoints] = circle->pos; int indices[numpoints * 3]; - for (int i = 0; i < numpoints; i++) { + for (int j = 0; j < numpoints; j++) { - points[i] = circle->pos + Vector2(Math::sin(i * Math_PI * 2.0 / numpoints), Math::cos(i * Math_PI * 2.0 / numpoints)) * circle->radius; - indices[i * 3 + 0] = i; - indices[i * 3 + 1] = (i + 1) % numpoints; - indices[i * 3 + 2] = numpoints; + points[j] = circle->pos + Vector2(Math::sin(j * Math_PI * 2.0 / numpoints), Math::cos(j * Math_PI * 2.0 / numpoints)) * circle->radius; + indices[j * 3 + 0] = j; + indices[j * 3 + 1] = (j + 1) % numpoints; + indices[j * 3 + 2] = numpoints; } _bind_canvas_texture(RID(), RID()); @@ -1142,6 +1156,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur void RasterizerCanvasGLES3::_copy_texscreen(const Rect2 &p_rect) { + ERR_FAIL_COND_MSG(storage->frame.current_rt->effects.mip_maps[0].sizes.size() == 0, "Can't use screen texture copying in a render target configured without copy buffers."); + glDisable(GL_BLEND); state.canvas_texscreen_used = true; @@ -1223,10 +1239,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); glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); @@ -1310,6 +1322,8 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); glBindTexture(GL_TEXTURE_2D, skeleton->texture); state.using_skeleton = true; + state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM, state.skeleton_transform); + state.canvas_shader.set_uniform(CanvasShaderGLES3::SKELETON_TRANSFORM_INVERSE, state.skeleton_transform_inverse); } else { state.using_skeleton = false; } @@ -1344,7 +1358,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons last_blend_mode = last_blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED ? last_blend_mode : -1; } - if (shader_ptr != shader_cache) { + if (shader_ptr != shader_cache || rebind_shader) { if (shader_ptr->canvas_item.uses_time) { VisualServerRaster::redraw_request(); @@ -1555,15 +1569,12 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, has_shadow); if (has_shadow) { state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_USE_GRADIENT, light->shadow_gradient_length > 0); - switch (light->shadow_filter) { - - case VS::CANVAS_LIGHT_FILTER_NONE: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, true); break; - case VS::CANVAS_LIGHT_FILTER_PCF3: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, true); break; - case VS::CANVAS_LIGHT_FILTER_PCF5: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, true); break; - case VS::CANVAS_LIGHT_FILTER_PCF7: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, true); break; - case VS::CANVAS_LIGHT_FILTER_PCF9: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, true); break; - case VS::CANVAS_LIGHT_FILTER_PCF13: state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, true); break; - } + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_NEAREST, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_NONE); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF3, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF3); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF5, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF5); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF7, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF7); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF9, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF9); + state.canvas_shader.set_conditional(CanvasShaderGLES3::SHADOW_FILTER_PCF13, light->shadow_filter == VS::CANVAS_LIGHT_FILTER_PCF13); } bool light_rebind = state.canvas_shader.bind(); @@ -1573,6 +1584,11 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons state.canvas_shader.set_uniform(CanvasShaderGLES3::FINAL_MODULATE, state.canvas_item_modulate); state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform); state.canvas_shader.set_uniform(CanvasShaderGLES3::EXTRA_MATRIX, Transform2D()); + if (storage->frame.current_rt) { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0 / storage->frame.current_rt->width, 1.0 / storage->frame.current_rt->height)); + } else { + state.canvas_shader.set_uniform(CanvasShaderGLES3::SCREEN_PIXEL_SIZE, Vector2(1.0, 1.0)); + } } glBindBufferBase(GL_UNIFORM_BUFFER, 1, static_cast<LightInternal *>(light->light_internal.get_data())->ubo); @@ -1661,6 +1677,14 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons if (current_clip) { glDisable(GL_SCISSOR_TEST); } + //disable states that may have been used + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, false); } void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) { @@ -1687,6 +1711,8 @@ void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_s light = light->shadows_next_ptr; } + + canvas_end(); } void RasterizerCanvasGLES3::canvas_light_shadow_buffer_update(RID p_buffer, const Transform2D &p_light_xform, int p_light_mask, float p_near, float p_far, LightOccluderInstance *p_occluders, CameraMatrix *p_xform_cache) { @@ -1871,13 +1897,46 @@ 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(); int window_h = window_size.height; int window_w = window_size.width; - glBindFramebuffer(GL_FRAMEBUFFER, storage->system_fbo); + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); glViewport(0, 0, window_size.width, window_size.height); canvas_begin(); @@ -1989,13 +2048,14 @@ void RasterizerCanvasGLES3::initialize() { glEnableVertexAttribArray(VS::ARRAY_VERTEX); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, (float *)0 + 2); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind } { 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); @@ -2025,16 +2085,16 @@ void RasterizerCanvasGLES3::initialize() { } glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); + glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, stride, NULL); if (i & 1) { glEnableVertexAttribArray(VS::ARRAY_COLOR); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + color_ofs); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); } if (i & 2) { glEnableVertexAttribArray(VS::ARRAY_TEX_UV); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + uv_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(uv_ofs)); } glBindVertexArray(0); @@ -2043,6 +2103,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); @@ -2060,6 +2121,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 bc4ea80328..bf5ef30820 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -35,6 +35,7 @@ #include "servers/visual/rasterizer.h" #include "shaders/canvas_shadow.glsl.gen.h" +#include "shaders/lens_distorted.glsl.gen.h" class RasterizerSceneGLES3; @@ -72,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; @@ -141,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 d3f6dcd497..ea15a278d6 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -32,7 +32,6 @@ #include "core/os/os.h" #include "core/project_settings.h" -#include "gl_context/context_gl.h" RasterizerStorage *RasterizerGLES3::get_storage() { @@ -73,12 +72,12 @@ RasterizerScene *RasterizerGLES3::get_scene() { #define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 #define _EXT_DEBUG_OUTPUT 0x92E0 -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) -#define GLAPIENTRY APIENTRY -#else -#define GLAPIENTRY +#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 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) @@ -123,6 +122,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, @@ -252,11 +252,16 @@ void RasterizerGLES3::set_current_render_target(RID p_render_target) { } } -void RasterizerGLES3::restore_render_target() { +void RasterizerGLES3::restore_render_target(bool p_3d_was_drawn) { ERR_FAIL_COND(storage->frame.current_rt == NULL); RasterizerStorageGLES3::RenderTarget *rt = storage->frame.current_rt; - glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); + if (p_3d_was_drawn && rt->external.fbo != 0) { + // our external render buffer is now leading, render 2d into that. + glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, rt->fbo); + } glViewport(0, 0, rt->width, rt->height); } @@ -268,7 +273,7 @@ void RasterizerGLES3::clear_render_target(const Color &p_color) { storage->frame.clear_request_color = p_color; } -void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) { +void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter) { if (p_image.is_null() || p_image->empty()) return; @@ -291,7 +296,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c canvas->canvas_begin(); RID texture = storage->texture_create(); - storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER); + storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, p_use_filter ? VS::TEXTURE_FLAG_FILTER : 0); storage->texture_set_data(texture, p_image); Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height()); @@ -338,7 +343,11 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re #if 1 Size2 win_size = OS::get_singleton()->get_window_size(); - glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo); + if (rt->external.fbo != 0) { + glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->external.fbo); + } else { + glBindFramebuffer(GL_READ_FRAMEBUFFER, rt->fbo); + } glReadBuffer(GL_COLOR_ATTACHMENT0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); glBlitFramebuffer(0, 0, rt->width, rt->height, p_screen_rect.position.x, win_size.height - p_screen_rect.position.y - p_screen_rect.size.height, p_screen_rect.position.x + p_screen_rect.size.width, win_size.height - p_screen_rect.position.y, GL_COLOR_BUFFER_BIT, GL_NEAREST); @@ -359,6 +368,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()) { @@ -405,10 +434,10 @@ void RasterizerGLES3::make_current() { void RasterizerGLES3::register_config() { - GLOBAL_DEF("rendering/quality/filters/use_nearest_mipmap_filter", false); 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..8fa208a1aa 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -51,14 +51,15 @@ public: virtual RasterizerCanvas *get_canvas(); virtual RasterizerScene *get_scene(); - virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale); + virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale, bool p_use_filter = true); virtual void initialize(); virtual void begin_frame(double frame_step); virtual void set_current_render_target(RID p_render_target); - virtual void restore_render_target(); + virtual void restore_render_target(bool p_3d_was_drawn); 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 086829f9ba..35f414cf09 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -34,6 +34,7 @@ #include "core/os/os.h" #include "core/project_settings.h" #include "rasterizer_canvas_gles3.h" +#include "servers/camera/camera_feed.h" #include "servers/visual/visual_server_raster.h" #ifndef GLES_OVER_GL @@ -51,26 +52,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]; @@ -673,7 +654,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()) { @@ -811,6 +792,14 @@ void RasterizerSceneGLES3::environment_set_sky_custom_fov(RID p_env, float p_sca env->sky_custom_fov = p_scale; } +void RasterizerSceneGLES3::environment_set_sky_orientation(RID p_env, const Basis &p_orientation) { + + Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->sky_orientation = p_orientation; +} + void RasterizerSceneGLES3::environment_set_bg_color(RID p_env, const Color &p_color) { Environment *env = environment_owner.getornull(p_env); @@ -842,6 +831,12 @@ void RasterizerSceneGLES3::environment_set_ambient_light(RID p_env, const Color env->ambient_energy = p_energy; env->ambient_sky_contribution = p_sky_contribution; } +void RasterizerSceneGLES3::environment_set_camera_feed_id(RID p_env, int p_camera_feed_id) { + Environment *env = environment_owner.getornull(p_env); + ERR_FAIL_COND(!env); + + env->camera_feed_id = p_camera_feed_id; +} void RasterizerSceneGLES3::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) { @@ -866,7 +861,7 @@ void RasterizerSceneGLES3::environment_set_dof_blur_near(RID p_env, bool p_enabl env->dof_blur_near_amount = p_amount; env->dof_blur_near_quality = p_quality; } -void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) { +void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -879,6 +874,7 @@ void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_ env->glow_blend_mode = p_blend_mode; env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold; env->glow_hdr_bleed_scale = p_hdr_bleed_scale; + env->glow_hdr_luminance_cap = p_hdr_luminance_cap; env->glow_bicubic_upscale = p_bicubic_upscale; } void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) { @@ -954,13 +950,14 @@ void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, const C env->fog_sun_amount = p_sun_amount; } -void RasterizerSceneGLES3::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) { +void RasterizerSceneGLES3::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, 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_end = p_depth_end; env->fog_depth_curve = p_depth_curve; env->fog_transmit_enabled = p_transmit; env->fog_transmit_curve = p_transmit_curve; @@ -1011,7 +1008,7 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) { if (!light_instance->light_ptr) { memdelete(light_instance); - ERR_FAIL_COND_V(!light_instance->light_ptr, RID()); + ERR_FAIL_V_MSG(RID(), "Condition ' !light_instance->light_ptr ' is true."); } light_instance->self = light_instance_owner.make_rid(light_instance); @@ -1071,12 +1068,11 @@ void RasterizerSceneGLES3::gi_probe_instance_set_light_data(RID p_probe, RID p_b if (p_data.is_valid()) { RasterizerStorageGLES3::GIProbeData *gipd = storage->gi_probe_data_owner.getornull(p_data); ERR_FAIL_COND(!gipd); - if (gipd) { - gipi->tex_cache = gipd->tex_id; - gipi->cell_size_cache.x = 1.0 / gipd->width; - gipi->cell_size_cache.y = 1.0 / gipd->height; - gipi->cell_size_cache.z = 1.0 / gipd->depth; - } + + gipi->tex_cache = gipd->tex_id; + gipi->cell_size_cache.x = 1.0 / gipd->width; + gipi->cell_size_cache.y = 1.0 / gipd->height; + gipi->cell_size_cache.z = 1.0 / gipd->depth; } } void RasterizerSceneGLES3::gi_probe_instance_set_transform_to_data(RID p_probe, const Transform &p_xform) { @@ -1124,13 +1120,23 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m if (state.current_depth_draw != p_material->shader->spatial.depth_draw_mode) { switch (p_material->shader->spatial.depth_draw_mode) { - case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS: + case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS: { + glDepthMask(GL_TRUE); + // If some transparent objects write to depth, we need to re-copy depth texture when we need it + if (p_alpha_pass && !state.used_depth_prepass) { + state.prepared_depth_texture = false; + } + } break; case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_OPAQUE: { glDepthMask(!p_alpha_pass); } break; case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALWAYS: { glDepthMask(GL_TRUE); + // If some transparent objects write to depth, we need to re-copy depth texture when we need it + if (p_alpha_pass) { + state.prepared_depth_texture = false; + } } break; case RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER: { glDepthMask(GL_FALSE); @@ -1202,7 +1208,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]); @@ -1214,6 +1220,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m } t = t->get_ptr(); //resolve for proxies + #ifdef TOOLS_ENABLED if (t->detect_3d) { t->detect_3d(t->detect_3d_ud); @@ -1266,22 +1273,29 @@ 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; case ShaderLanguage::TYPE_ISAMPLER2DARRAY: case ShaderLanguage::TYPE_USAMPLER2DARRAY: case ShaderLanguage::TYPE_SAMPLER2DARRAY: { + + target = GL_TEXTURE_2D_ARRAY; + tex = storage->resources.white_tex_array; + + //switch (texture_hints[i]) { // TODO + //} + } break; + + default: { + } } } @@ -1379,17 +1393,17 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4; glEnableVertexAttribArray(8); - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, NULL); glVertexAttribDivisor(8, 1); glEnableVertexAttribArray(9); - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 4 * 4); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(4 * 4)); glVertexAttribDivisor(9, 1); int color_ofs; if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) { glEnableVertexAttribArray(10); - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 8 * 4); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(8 * 4)); glVertexAttribDivisor(10, 1); color_ofs = 12 * 4; } else { @@ -1408,14 +1422,14 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo } break; case VS::MULTIMESH_COLOR_8BIT: { glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, ((uint8_t *)NULL) + color_ofs); + glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); glVertexAttribDivisor(11, 1); custom_data_ofs += 4; } break; case VS::MULTIMESH_COLOR_FLOAT: { glEnableVertexAttribArray(11); - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + color_ofs); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(color_ofs)); glVertexAttribDivisor(11, 1); custom_data_ofs += 4 * 4; } break; @@ -1429,13 +1443,13 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo } break; case VS::MULTIMESH_CUSTOM_DATA_8BIT: { glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, ((uint8_t *)NULL) + custom_data_ofs); + glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); glVertexAttribDivisor(12, 1); } break; case VS::MULTIMESH_CUSTOM_DATA_FLOAT: { glEnableVertexAttribArray(12); - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + custom_data_ofs); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(custom_data_ofs)); glVertexAttribDivisor(12, 1); } break; } @@ -1449,7 +1463,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 particle_writer = particle_vector.write(); + particle_array = particle_writer.ptr(); + glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), particle_array); +#endif SortArray<RasterizerGLES3Particle, RasterizerGLES3ParticleSort> sorter; @@ -1461,7 +1484,17 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo sorter.sort(particle_array, particles->amount); +#ifndef __EMSCRIPTEN__ glUnmapBuffer(GL_ARRAY_BUFFER); +#else + particle_writer.release(); + 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 @@ -1492,23 +1525,25 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo if (particles->draw_order != VS::PARTICLES_DRAW_ORDER_LIFETIME) { glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 3); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); glVertexAttribDivisor(9, 1); glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); glVertexAttribDivisor(10, 1); glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); glVertexAttribDivisor(11, 1); glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 2); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); glVertexAttribDivisor(12, 1); } } break; + default: { + } } } @@ -1612,11 +1647,10 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(c.texture); - t = t->get_ptr(); //resolve for proxies - if (t->redraw_if_visible) { VisualServerRaster::redraw_request(); } + t = t->get_ptr(); //resolve for proxies #ifdef TOOLS_ENABLED if (t->detect_3d) { @@ -1643,7 +1677,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { glEnableVertexAttribArray(VS::ARRAY_NORMAL); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.normals.ptr()); - glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, false, sizeof(Vector3), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, false, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Vector3) * vertices; } else { @@ -1655,7 +1689,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { glEnableVertexAttribArray(VS::ARRAY_TANGENT); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Plane) * vertices, c.tangents.ptr()); - glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, false, sizeof(Plane), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, false, sizeof(Plane), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Plane) * vertices; } else { @@ -1667,7 +1701,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { glEnableVertexAttribArray(VS::ARRAY_COLOR); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Color) * vertices, c.colors.ptr()); - glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, false, sizeof(Color), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Color) * vertices; } else { @@ -1680,7 +1714,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs.ptr()); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Vector2) * vertices; } else { @@ -1692,7 +1726,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { glEnableVertexAttribArray(VS::ARRAY_TEX_UV2); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs2.ptr()); - glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, false, sizeof(Vector2), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, false, sizeof(Vector2), CAST_INT_TO_UCHAR_PTR(buf_ofs)); buf_ofs += sizeof(Vector2) * vertices; } else { @@ -1702,7 +1736,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { glEnableVertexAttribArray(VS::ARRAY_VERTEX); glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.vertices.ptr()); - glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, sizeof(Vector3), ((uint8_t *)NULL) + buf_ofs); + glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, false, sizeof(Vector3), CAST_INT_TO_UCHAR_PTR(buf_ofs)); glDrawArrays(gl_primitive[c.primitive], 0, c.vertices.size()); } @@ -1731,19 +1765,19 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { if (amount - split > 0) { glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 3); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 4); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 4)); glVertexAttribDivisor(9, 1); glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 5); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 5)); glVertexAttribDivisor(10, 1); glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + 0); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + 0)); glVertexAttribDivisor(11, 1); glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + stride * split + sizeof(float) * 4 * 2); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(stride * split + sizeof(float) * 4 * 2)); glVertexAttribDivisor(12, 1); #ifdef DEBUG_ENABLED @@ -1769,19 +1803,19 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { if (split > 0) { glEnableVertexAttribArray(8); //xform x - glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 3); + glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 3)); glVertexAttribDivisor(8, 1); glEnableVertexAttribArray(9); //xform y - glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 4); + glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 4)); glVertexAttribDivisor(9, 1); glEnableVertexAttribArray(10); //xform z - glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 5); + glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 5)); glVertexAttribDivisor(10, 1); glEnableVertexAttribArray(11); //color - glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0); + glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, NULL); glVertexAttribDivisor(11, 1); glEnableVertexAttribArray(12); //custom - glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + sizeof(float) * 4 * 2); + glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(sizeof(float) * 4 * 2)); glVertexAttribDivisor(12, 1); #ifdef DEBUG_ENABLED @@ -1815,6 +1849,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { storage->info.render.vertices_count += s->index_array_len * amount; } else #endif + if (s->index_array_len > 0) { glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount); @@ -1830,6 +1865,8 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } } break; + default: { + } } } @@ -2025,7 +2062,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ int current_blend_mode = -1; int prev_shading = -1; - RID prev_skeleton; + RasterizerStorageGLES3::Skeleton *prev_skeleton = NULL; state.scene_shader.set_conditional(SceneShaderGLES3::SHADELESS, true); //by default unshaded (easier to set) @@ -2039,7 +2076,10 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ RenderList::Element *e = p_elements[i]; RasterizerStorageGLES3::Material *material = e->material; - RID skeleton = e->instance->skeleton; + RasterizerStorageGLES3::Skeleton *skeleton = NULL; + if (e->instance->skeleton.is_valid()) { + skeleton = storage->skeleton_owner.getornull(e->instance->skeleton); + } bool rebind = first; @@ -2186,15 +2226,14 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ } if (prev_skeleton != skeleton) { - if (prev_skeleton.is_valid() != skeleton.is_valid()) { - state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON, skeleton.is_valid()); + if ((prev_skeleton == NULL) != (skeleton == NULL)) { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_SKELETON, skeleton != NULL); rebind = true; } - if (skeleton.is_valid()) { - RasterizerStorageGLES3::Skeleton *sk = storage->skeleton_owner.getornull(skeleton); + if (skeleton) { glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1); - glBindTexture(GL_TEXTURE_2D, sk->texture); + glBindTexture(GL_TEXTURE_2D, skeleton->texture); } } @@ -2221,7 +2260,6 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ _set_cull(e->sort_key & RenderList::SORT_KEY_MIRROR_FLAG, e->sort_key & RenderList::SORT_KEY_CULL_DISABLED_FLAG, p_reverse_cull); - state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror ? -1.0 : 1.0); state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform); _render_geometry(e); @@ -2325,9 +2363,13 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G state.used_screen_texture = true; } + if (p_material->shader->spatial.uses_depth_texture) { + state.used_depth_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 != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) + if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) || p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_NEVER || p_material->shader->spatial.no_depth_test || p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_OFF) 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 != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { @@ -2344,7 +2386,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G has_alpha = false; } - RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element(); + RenderList::Element *e = (has_alpha || p_material->shader->spatial.no_depth_test) ? render_list.add_alpha_element() : render_list.add_element(); if (!e) return; @@ -2389,7 +2431,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G e->sort_key |= SORT_KEY_LIGHTMAP_CAPTURE_FLAG; } - e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; + e->sort_key |= (uint64_t(p_material->render_priority) + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; } /* @@ -2425,7 +2467,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G } } -void RasterizerSceneGLES3::_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 RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy, const Basis &p_sky_orientation) { ERR_FAIL_COND(!p_sky); @@ -2517,7 +2559,12 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, !asymmetrical); storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_MULTIPLIER, true); storage->shaders.copy.bind(); + storage->shaders.copy.set_uniform(CopyShaderGLES3::MULTIPLIER, p_energy); + + // don't know why but I always have problems setting a uniform mat3, so we're using a transform + storage->shaders.copy.set_uniform(CopyShaderGLES3::SKY_TRANSFORM, Transform(p_sky_orientation, Vector3(0.0, 0.0, 0.0)).affine_inverse()); + if (asymmetrical) { // pack the bits we need from our projection matrix storage->shaders.copy.set_uniform(CopyShaderGLES3::ASYM_PROJ, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1]); @@ -2535,7 +2582,8 @@ 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) { + Transform sky_orientation; //store camera into ubo store_camera(p_cam_projection, state.ubo_data.projection_matrix); @@ -2576,6 +2624,9 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr state.ubo_data.bg_color[2] = bg_color.b; state.ubo_data.bg_color[3] = bg_color.a; + //use the inverse of our sky_orientation, we may need to skip this if we're using a reflection probe? + sky_orientation = Transform(env->sky_orientation, Vector3(0.0, 0.0, 0.0)).affine_inverse(); + state.env_radiance_data.ambient_contribution = env->ambient_sky_contribution; state.ubo_data.ambient_occlusion_affect_light = env->ssao_light_affect; state.ubo_data.ambient_occlusion_affect_ssao = env->ssao_ao_channel_affect; @@ -2586,7 +2637,8 @@ 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; + state.ubo_data.fog_density = linear_fog.a; Color linear_sun = env->fog_sun_color.to_linear(); state.ubo_data.fog_sun_color_amount[0] = linear_sun.r; @@ -2595,6 +2647,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr state.ubo_data.fog_sun_color_amount[3] = env->fog_sun_amount; state.ubo_data.fog_depth_enabled = env->fog_depth_enabled; state.ubo_data.fog_depth_begin = env->fog_depth_begin; + state.ubo_data.fog_depth_end = env->fog_depth_end; state.ubo_data.fog_depth_curve = env->fog_depth_curve; state.ubo_data.fog_transmit_enabled = env->fog_transmit_enabled; state.ubo_data.fog_transmit_curve = env->fog_transmit_curve; @@ -2642,7 +2695,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr //fill up environment - store_transform(p_cam_transform, state.env_radiance_data.transform); + store_transform(sky_orientation * p_cam_transform, state.env_radiance_data.transform); glBindBuffer(GL_UNIFORM_BUFFER, state.env_radiance_ubo); glBufferSubData(GL_UNIFORM_BUFFER, 0, sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_data); @@ -2715,9 +2768,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform width /= 2; height /= 2; - if (j == 0) { - - } else if (j == 1) { + if (j == 1) { x += width; } else if (j == 2) { y += height; @@ -2730,9 +2781,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform height /= 2; - if (j == 0) { - - } else { + if (j != 0) { y += height; } } @@ -2749,7 +2798,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[j].camera * modelview; - store_camera(shadow_mtx, &ubo_data.shadow_matrix1[16 * j]); + store_camera(shadow_mtx, &ubo_data.shadow.matrix[16 * j]); ubo_data.light_clamp[0] = atlas_rect.position.x; ubo_data.light_clamp[1] = atlas_rect.position.y; @@ -2779,7 +2828,7 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result, int p_light_c for (int i = 0; i < p_light_cull_count; i++) { - ERR_BREAK(i >= RenderList::MAX_LIGHTS); + ERR_BREAK(i >= render_list.max_lights); LightInstance *li = light_instance_owner.getptr(p_light_cull_result[i]); @@ -2860,7 +2909,7 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result, int p_light_c Transform proj = (p_camera_inverse_transform * li->transform).inverse(); - store_transform(proj, ubo_data.shadow_matrix1); + store_transform(proj, ubo_data.shadow.matrix1); ubo_data.light_params[3] = 1.0; //means it has shadow ubo_data.light_clamp[0] = float(x) / atlas_size; @@ -2949,7 +2998,7 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result, int p_light_c CameraMatrix shadow_mtx = rectm * bias * li->shadow_transform[0].camera * modelview; - store_camera(shadow_mtx, ubo_data.shadow_matrix1); + store_camera(shadow_mtx, ubo_data.shadow.matrix1); } li->light_index = state.spot_light_count; @@ -3036,19 +3085,17 @@ 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; 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; } reflection_ubo.ambient[0] = ambient_linear.r; reflection_ubo.ambient[1] = ambient_linear.g; reflection_ubo.ambient[2] = ambient_linear.b; - reflection_ubo.ambient[3] = 0; + reflection_ubo.ambient[3] = 0; //not used in exterior mode, since it just blends with regular ambient light } int cell_size = reflection_atlas->size / reflection_atlas->subdiv; @@ -3087,7 +3134,7 @@ void RasterizerSceneGLES3::_copy_screen(bool p_invalidate_color, bool p_invalida GLenum attachments[2] = { GL_COLOR_ATTACHMENT0, - GL_DEPTH_STENCIL_ATTACHMENT + GL_DEPTH_ATTACHMENT }; glInvalidateFramebuffer(GL_FRAMEBUFFER, p_invalidate_depth ? 2 : 1, attachments); @@ -3132,6 +3179,8 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p current_material_index = 0; state.used_sss = false; state.used_screen_texture = false; + state.used_depth_texture = false; + //fill list for (int i = 0; i < p_cull_count; i++) { @@ -3146,10 +3195,10 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p int ssize = mesh->surfaces.size(); - for (int i = 0; i < ssize; i++) { + for (int j = 0; j < ssize; j++) { - int mat_idx = inst->materials[i].is_valid() ? i : -1; - RasterizerStorageGLES3::Surface *s = mesh->surfaces[i]; + int mat_idx = inst->materials[j].is_valid() ? j : -1; + RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; _add_geometry(s, inst, NULL, mat_idx, p_depth_pass, p_shadow_pass); } @@ -3170,9 +3219,9 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p int ssize = mesh->surfaces.size(); - for (int i = 0; i < ssize; i++) { + for (int j = 0; j < ssize; j++) { - RasterizerStorageGLES3::Surface *s = mesh->surfaces[i]; + RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; _add_geometry(s, inst, multi_mesh, -1, p_depth_pass, p_shadow_pass); } @@ -3190,9 +3239,9 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p RasterizerStorageGLES3::Particles *particles = storage->particles_owner.getptr(inst->base); ERR_CONTINUE(!particles); - for (int i = 0; i < particles->draw_passes.size(); i++) { + for (int j = 0; j < particles->draw_passes.size(); j++) { - RID pmesh = particles->draw_passes[i]; + RID pmesh = particles->draw_passes[j]; if (!pmesh.is_valid()) continue; RasterizerStorageGLES3::Mesh *mesh = storage->mesh_owner.get(pmesh); @@ -3201,14 +3250,16 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p int ssize = mesh->surfaces.size(); - for (int j = 0; j < ssize; j++) { + for (int k = 0; k < ssize; k++) { - RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; + RasterizerStorageGLES3::Surface *s = mesh->surfaces[k]; _add_geometry(s, inst, particles, -1, p_depth_pass, p_shadow_pass); } } } break; + default: { + } } } } @@ -3246,6 +3297,29 @@ void RasterizerSceneGLES3::_blur_effect_buffer() { } } +void RasterizerSceneGLES3::_prepare_depth_texture() { + if (!state.prepared_depth_texture) { + //resolve depth buffer + glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); + glReadBuffer(GL_COLOR_ATTACHMENT0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); + glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_DEPTH_BUFFER_BIT, GL_NEAREST); + glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); + state.prepared_depth_texture = true; + } +} + +void RasterizerSceneGLES3::_bind_depth_texture() { + if (!state.bound_depth_texture) { + ERR_FAIL_COND(!state.prepared_depth_texture); + //bind depth for read + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 8); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); + state.bound_depth_texture = true; + } +} + void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_cam_projection) { glDepthMask(GL_FALSE); @@ -3253,6 +3327,8 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glDisable(GL_CULL_FACE); glDisable(GL_BLEND); + _prepare_depth_texture(); + if (env->ssao_enabled || env->ssr_enabled) { //copy normal and roughness to effect buffer @@ -3585,7 +3661,6 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p if (storage->frame.current_rt->buffers.active) { //transfer to effect buffer if using buffers, also resolve MSAA - glReadBuffer(GL_COLOR_ATTACHMENT0); glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo); glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_COLOR_BUFFER_BIT, GL_NEAREST); @@ -3594,12 +3669,16 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } - if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] || storage->frame.current_rt->width < 4 || storage->frame.current_rt->height < 4) { //no post process on small render targets //no environment or transparent render, simply return and convert to SRGB - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); + if (storage->frame.current_rt->external.fbo != 0) { + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); + } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); - storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]); storage->shaders.copy.set_conditional(CopyShaderGLES3::V_FLIP, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP]); storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]); storage->shaders.copy.bind(); @@ -3896,6 +3975,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::GLOW_STRENGTH, env->glow_strength); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LUMINANCE_CAP, env->glow_hdr_luminance_cap); glActiveTexture(GL_TEXTURE0); if (i == 0) { @@ -3938,14 +4018,18 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); } - glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); + if (storage->frame.current_rt->external.fbo != 0) { + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->external.fbo); + } else { + glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); + } glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, composite_from); 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); @@ -4032,7 +4116,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); @@ -4097,15 +4181,37 @@ 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; glDepthFunc(GL_LEQUAL); - state.used_contact_shadows = true; + state.used_contact_shadows = false; + state.prepared_depth_texture = false; + state.bound_depth_texture = false; + + for (int i = 0; i < p_light_cull_count; i++) { - if (!storage->config.no_depth_prepass && storage->frame.current_rt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { //detect with state.used_contact_shadows too + ERR_BREAK(i >= render_list.max_lights); + + LightInstance *li = light_instance_owner.getptr(p_light_cull_result[i]); + if (li->light_ptr->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] > CMP_EPSILON) { + state.used_contact_shadows = true; + } + } + + // Do depth prepass if it's explicitly enabled + bool use_depth_prepass = storage->config.use_depth_prepass; + + // If contact shadows are used then we need to do depth prepass even if it's otherwise disabled + use_depth_prepass = use_depth_prepass || state.used_contact_shadows; + + // Never do depth prepass if effects are disabled or if we render overdraws + use_depth_prepass = use_depth_prepass && storage->frame.current_rt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS]; + use_depth_prepass = use_depth_prepass && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW; + + if (use_depth_prepass) { //pre z pass glDisable(GL_BLEND); @@ -4119,7 +4225,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glColorMask(0, 0, 0, 0); glClearDepth(1.0f); - glClear(GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); + glClear(GL_DEPTH_BUFFER_BIT); render_list.clear(); _fill_render_list(p_cull_result, p_cull_count, true, false); @@ -4132,22 +4238,15 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const if (state.used_contact_shadows) { - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->fbo); - glBlitFramebuffer(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, 0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height, GL_DEPTH_BUFFER_BIT, GL_NEAREST); - glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); - //bind depth for read - glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 8); - glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); + _prepare_depth_texture(); + _bind_depth_texture(); } fb_cleared = true; render_pass++; - state.using_contact_shadows = true; + state.used_depth_prepass = true; } else { - state.using_contact_shadows = false; + state.used_depth_prepass = false; } _setup_lights(p_light_cull_result, p_light_cull_count, p_cam_transform.affine_inverse(), p_cam_projection, p_shadow_atlas); @@ -4194,12 +4293,12 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const } else { - use_mrt = env && (state.used_sss || env->ssao_enabled || env->ssr_enabled); //only enable MRT rendering if any of these is enabled + use_mrt = env && (state.used_sss || env->ssao_enabled || env->ssr_enabled || env->dof_blur_far_enabled || env->dof_blur_near_enabled); //only enable MRT rendering if any of these is enabled //effects disabled and transparency also prevent using MRTs use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]; use_mrt = use_mrt && !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_NO_3D_EFFECTS]; use_mrt = use_mrt && state.debug_draw != VS::VIEWPORT_DEBUG_DRAW_OVERDRAW; - use_mrt = use_mrt && env && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS); + use_mrt = use_mrt && (env->bg_mode != VS::ENV_BG_KEEP && env->bg_mode != VS::ENV_BG_CANVAS); glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); @@ -4231,6 +4330,10 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const if (storage->frame.current_rt->buffers.active) { current_fbo = storage->frame.current_rt->buffers.fbo; } else { + if (storage->frame.current_rt->effects.mip_maps[0].sizes.size() == 0) { + ERR_PRINT_ONCE("Can't use canvas background mode in a render target configured without sampling"); + return; + } current_fbo = storage->frame.current_rt->effects.mip_maps[0].sizes[0].fbo; } @@ -4244,12 +4347,14 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const } if (!fb_cleared) { - glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0, 0); + glClearDepth(1.0f); + glClear(GL_DEPTH_BUFFER_BIT); } Color clear_color(0, 0, 0, 0); RasterizerStorageGLES3::Sky *sky = NULL; + Ref<CameraFeed> feed; GLuint env_radiance_tex = 0; if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_OVERDRAW) { @@ -4284,6 +4389,9 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const clear_color = env->bg_color.to_linear(); storage->frame.clear_request = false; + } else if (env->bg_mode == VS::ENV_BG_CAMERA_FEED) { + feed = CameraServer::get_singleton()->get_feed_by_id(env->camera_feed_id); + storage->frame.clear_request = false; } else { storage->frame.clear_request = false; } @@ -4292,10 +4400,11 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular } + VS::EnvironmentBG bg_mode = (!env || (probe && env->bg_mode == VS::ENV_BG_CANVAS)) ? VS::ENV_BG_CLEAR_COLOR : env->bg_mode; //if no environment, or canvas while rendering a probe (invalid use case), use color. + if (env) { - switch (env->bg_mode) { + switch (bg_mode) { case VS::ENV_BG_COLOR_SKY: - case VS::ENV_BG_SKY: sky = storage->sky_owner.getornull(env->sky); @@ -4333,9 +4442,72 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); break; + case VS::ENV_BG_CAMERA_FEED: + if (feed.is_valid() && (feed->get_base_width() > 0) && (feed->get_base_height() > 0)) { + // copy our camera feed to our background + + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, true); + + if (feed->get_datatype() == CameraFeed::FEED_RGB) { + RID camera_RGBA = feed->get_texture(CameraServer::FEED_RGBA_IMAGE); + + VS::get_singleton()->texture_bind(camera_RGBA, 0); + } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR) { + RID camera_YCbCr = feed->get_texture(CameraServer::FEED_YCBCR_IMAGE); + + VS::get_singleton()->texture_bind(camera_YCbCr, 0); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true); + + } else if (feed->get_datatype() == CameraFeed::FEED_YCBCR_SEP) { + RID camera_Y = feed->get_texture(CameraServer::FEED_Y_IMAGE); + RID camera_CbCr = feed->get_texture(CameraServer::FEED_CBCR_IMAGE); + + VS::get_singleton()->texture_bind(camera_Y, 0); + VS::get_singleton()->texture_bind(camera_CbCr, 1); + + storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, true); + }; + + storage->shaders.copy.bind(); + storage->shaders.copy.set_uniform(CopyShaderGLES3::DISPLAY_TRANSFORM, feed->get_transform()); + + _copy_screen(true, true); + + //turn off everything used + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_DISPLAY_TRANSFORM, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::SRGB_TO_LINEAR, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::SEP_CBCR_TEXTURE, false); + storage->shaders.copy.set_conditional(CopyShaderGLES3::YCBCR_TO_SRGB, false); + + //restore + glEnable(GL_BLEND); + glDepthMask(GL_TRUE); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + } else { + // don't have a feed, just show greenscreen :) + clear_color = Color(0.0, 1.0, 0.0, 1.0); + } + break; + default: { + } } } + if (probe && probe->probe_ptr->interior) { + env_radiance_tex = 0; //for rendering probe interiors, radiance must not be used. + } + state.texscreen_copied = false; glBlendEquation(GL_FUNC_ADD); @@ -4379,7 +4551,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const */ if (sky && sky->panorama.is_valid()) - _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy); + _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy, env->sky_orientation); } //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); @@ -4388,9 +4560,15 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const //state.scene_shader.set_conditional( SceneShaderGLES3::USE_FOG,false); if (use_mrt) { + _render_mrts(env, p_cam_projection); } else { - //FIXME: check that this is possible to use + // Here we have to do the blits/resolves that otherwise are done in the MRT rendering, in particular + // - prepare screen texture for any geometry that uses a shader with screen texture + // - prepare depth texture for any geometry that uses a shader with depth texture + + bool framebuffer_dirty = false; + if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_screen_texture) { glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); glReadBuffer(GL_COLOR_ATTACHMENT0); @@ -4399,12 +4577,25 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); _blur_effect_buffer(); - //restored framebuffer + framebuffer_dirty = true; + } + + if (storage->frame.current_rt && storage->frame.current_rt->buffers.active && state.used_depth_texture) { + _prepare_depth_texture(); + framebuffer_dirty = true; + } + + if (framebuffer_dirty) { + // Restore framebuffer glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); } } + if (storage->frame.current_rt && state.used_depth_texture && storage->frame.current_rt->buffers.active) { + _bind_depth_texture(); + } + if (storage->frame.current_rt && state.used_screen_texture && storage->frame.current_rt->buffers.active) { glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 7); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.mip_maps[0].color); @@ -4433,9 +4624,11 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const return; } + if (env && (env->dof_blur_far_enabled || env->dof_blur_near_enabled) && storage->frame.current_rt && storage->frame.current_rt->buffers.active) + _prepare_depth_texture(); _post_process(env, p_cam_projection); - - if (false && shadow_atlas) { + // Needed only for debugging + /* if (shadow_atlas && storage->frame.current_rt) { //_copy_texture_to_front_buffer(shadow_atlas->depth); storage->canvas->canvas_begin(); @@ -4445,7 +4638,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); } - if (false && storage->frame.current_rt) { + if (storage->frame.current_rt) { //_copy_texture_to_front_buffer(shadow_atlas->depth); storage->canvas->canvas_begin(); @@ -4455,7 +4648,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 16, storage->frame.current_rt->height / 16), Rect2(0, 0, 1, 1)); } - if (false && reflection_atlas && storage->frame.current_rt) { + if (reflection_atlas && storage->frame.current_rt) { //_copy_texture_to_front_buffer(shadow_atlas->depth); storage->canvas->canvas_begin(); @@ -4464,7 +4657,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); } - if (false && directional_shadow.fbo) { + if (directional_shadow.fbo) { //_copy_texture_to_front_buffer(shadow_atlas->depth); storage->canvas->canvas_begin(); @@ -4474,7 +4667,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); } - if (false && env_radiance_tex) { + if ( env_radiance_tex) { //_copy_texture_to_front_buffer(shadow_atlas->depth); storage->canvas->canvas_begin(); @@ -4485,8 +4678,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const storage->canvas->draw_generic_textured_rect(Rect2(0, 0, storage->frame.current_rt->width / 2, storage->frame.current_rt->height / 2), Rect2(0, 0, 1, 1)); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - } - + }*/ //disable all stuff } @@ -4501,7 +4693,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; @@ -4512,7 +4704,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ float bias = 0; float normal_bias = 0; - state.using_contact_shadows = false; + state.used_depth_prepass = false; CameraMatrix light_projection; Transform light_transform; @@ -4556,9 +4748,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ width /= 2; height /= 2; - if (p_pass == 0) { - - } else if (p_pass == 1) { + if (p_pass == 1) { x += width; } else if (p_pass == 2) { y += height; @@ -4583,7 +4773,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 @@ -4593,7 +4782,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]; @@ -4807,6 +4995,20 @@ bool RasterizerSceneGLES3::free(RID p_rid) { reflection_probe_instance_owner.free(p_rid); memdelete(reflection_instance); + } else if (environment_owner.owns(p_rid)) { + + Environment *environment = environment_owner.get(p_rid); + + environment_owner.free(p_rid); + memdelete(environment); + + } else if (gi_probe_instance_owner.owns(p_rid)) { + + GIProbeInstance *gi_probe_instance = gi_probe_instance_owner.get(p_rid); + + gi_probe_instance_owner.free(p_rid); + memdelete(gi_probe_instance); + } else { return false; } @@ -4871,10 +5073,11 @@ 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")); + render_list.max_lights = GLOBAL_DEF("rendering/limits/rendering/max_renderable_lights", (int)RenderList::DEFAULT_MAX_LIGHTS); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_lights", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_lights", PROPERTY_HINT_RANGE, "16,4096,1")); + render_list.max_reflections = GLOBAL_DEF("rendering/limits/rendering/max_renderable_reflections", (int)RenderList::DEFAULT_MAX_REFLECTIONS); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_reflections", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_reflections", PROPERTY_HINT_RANGE, "8,1024,1")); { //quad buffers @@ -4889,7 +5092,7 @@ void RasterizerSceneGLES3::initialize() { glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, 0); glEnableVertexAttribArray(VS::ARRAY_VERTEX); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, ((uint8_t *)NULL) + sizeof(Vector3)); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, CAST_INT_TO_UCHAR_PTR(sizeof(Vector3))); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind @@ -4969,7 +5172,7 @@ void RasterizerSceneGLES3::initialize() { glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &max_ubo_size); const int ubo_light_size = 160; state.ubo_light_size = ubo_light_size; - state.max_ubo_lights = MIN(RenderList::MAX_LIGHTS, max_ubo_size / ubo_light_size); + state.max_ubo_lights = MIN(render_list.max_lights, max_ubo_size / ubo_light_size); state.spot_array_tmp = (uint8_t *)memalloc(ubo_light_size * state.max_ubo_lights); state.omni_array_tmp = (uint8_t *)memalloc(ubo_light_size * state.max_ubo_lights); @@ -4994,7 +5197,7 @@ void RasterizerSceneGLES3::initialize() { state.scene_shader.add_custom_define("#define MAX_LIGHT_DATA_STRUCTS " + itos(state.max_ubo_lights) + "\n"); state.scene_shader.add_custom_define("#define MAX_FORWARD_LIGHTS " + itos(state.max_forward_lights_per_object) + "\n"); - state.max_ubo_reflections = MIN(RenderList::MAX_REFLECTIONS, max_ubo_size / sizeof(ReflectionProbeDataUBO)); + state.max_ubo_reflections = MIN(render_list.max_reflections, max_ubo_size / (int)sizeof(ReflectionProbeDataUBO)); state.reflection_array_tmp = (uint8_t *)memalloc(sizeof(ReflectionProbeDataUBO) * state.max_ubo_reflections); @@ -5014,7 +5217,7 @@ void RasterizerSceneGLES3::initialize() { { //reflection cubemaps int max_reflection_cubemap_sampler_size = 512; - int cube_size = max_reflection_cubemap_sampler_size; + int rcube_size = max_reflection_cubemap_sampler_size; glActiveTexture(GL_TEXTURE0); @@ -5024,10 +5227,10 @@ void RasterizerSceneGLES3::initialize() { GLenum format = GL_RGBA; GLenum type = use_float ? GL_HALF_FLOAT : GL_UNSIGNED_INT_2_10_10_10_REV; - while (cube_size >= 32) { + while (rcube_size >= 32) { ReflectionCubeMap cube; - cube.size = cube_size; + cube.size = rcube_size; glGenTextures(1, &cube.depth); glBindTexture(GL_TEXTURE_2D, cube.depth); @@ -5066,13 +5269,14 @@ void RasterizerSceneGLES3::initialize() { reflection_cubemaps.push_back(cube); - cube_size >>= 1; + rcube_size >>= 1; } } { 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); @@ -5106,7 +5310,7 @@ void RasterizerSceneGLES3::initialize() { GLOBAL_DEF("rendering/quality/subsurface_scattering/follow_surface", false); GLOBAL_DEF("rendering/quality/subsurface_scattering/weight_samples", true); - GLOBAL_DEF("rendering/quality/voxel_cone_tracing/high_quality", true); + GLOBAL_DEF("rendering/quality/voxel_cone_tracing/high_quality", false); } exposure_shrink_size = 243; @@ -5121,12 +5325,15 @@ void RasterizerSceneGLES3::initialize() { glGenTextures(1, &e.color); glBindTexture(GL_TEXTURE_2D, e.color); -#ifdef IPHONE_ENABLED - ///@TODO ugly hack to get around iOS not supporting 32bit single channel floating point textures... - glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_FLOAT, NULL); -#else - glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_FLOAT, NULL); -#endif + + if (storage->config.framebuffer_float_supported) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_FLOAT, NULL); + } else if (storage->config.framebuffer_half_float_supported) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_HALF_FLOAT, NULL); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, max_exposure_shrink_size, max_exposure_shrink_size, 0, GL_RED, GL_UNSIGNED_INT_2_10_10_10_REV, NULL); + } + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, e.color, 0); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index b4c4a0558f..3d09adcfeb 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -114,7 +114,7 @@ public: TonemapShaderGLES3 tonemap_shader; struct SceneDataUBO { - //this is a std140 compatible struct. Please read the OpenGL 3.3 Specificaiton spec before doing any changes + //this is a std140 compatible struct. Please read the OpenGL 3.3 Specification spec before doing any changes float projection_matrix[16]; float inv_projection_matrix[16]; float camera_inverse_matrix[16]; @@ -145,6 +145,8 @@ public: uint32_t fog_depth_enabled; float fog_depth_begin; + float fog_depth_end; + float fog_density; float fog_depth_curve; uint32_t fog_transmit_enabled; float fog_transmit_curve; @@ -202,7 +204,12 @@ public: bool cull_disabled; bool used_sss; bool used_screen_texture; - bool using_contact_shadows; + + bool used_depth_prepass; + + bool used_depth_texture; + bool prepared_depth_texture; + bool bound_depth_texture; VS::ViewportDebugDraw debug_draw; } state; @@ -363,11 +370,14 @@ public: RID sky; float sky_custom_fov; + Basis sky_orientation; Color bg_color; float bg_energy; float sky_ambient; + int camera_feed_id; + Color ambient_color; float ambient_energy; float ambient_sky_contribution; @@ -402,6 +412,7 @@ public: VS::EnvironmentGlowBlendMode glow_blend_mode; float glow_hdr_bleed_threshold; float glow_hdr_bleed_scale; + float glow_hdr_luminance_cap; bool glow_bicubic_upscale; VS::EnvironmentToneMapper tone_mapper; @@ -438,6 +449,7 @@ public: bool fog_depth_enabled; float fog_depth_begin; + float fog_depth_end; float fog_depth_curve; bool fog_transmit_enabled; float fog_transmit_curve; @@ -446,87 +458,78 @@ public: float fog_height_max; float fog_height_curve; - Environment() { - bg_mode = VS::ENV_BG_CLEAR_COLOR; - sky_custom_fov = 0.0; - bg_energy = 1.0; - sky_ambient = 0; - ambient_energy = 1.0; - ambient_sky_contribution = 0.0; - canvas_max_layer = 0; - - ssr_enabled = false; - ssr_max_steps = 64; - ssr_fade_in = 0.15; - ssr_fade_out = 2.0; - ssr_depth_tolerance = 0.2; - ssr_roughness = true; - - ssao_enabled = false; - ssao_intensity = 1.0; - ssao_radius = 1.0; - ssao_intensity2 = 1.0; - ssao_radius2 = 0.0; - ssao_bias = 0.01; - ssao_light_affect = 0; - ssao_ao_channel_affect = 0; - ssao_filter = VS::ENV_SSAO_BLUR_3x3; - ssao_quality = VS::ENV_SSAO_QUALITY_LOW; - ssao_bilateral_sharpness = 4; - - tone_mapper = VS::ENV_TONE_MAPPER_LINEAR; - tone_mapper_exposure = 1.0; - tone_mapper_exposure_white = 1.0; - auto_exposure = false; - auto_exposure_speed = 0.5; - auto_exposure_min = 0.05; - auto_exposure_max = 8; - auto_exposure_grey = 0.4; - - glow_enabled = false; - glow_levels = (1 << 2) | (1 << 4); - glow_intensity = 0.8; - glow_strength = 1.0; - glow_bloom = 0.0; - glow_blend_mode = VS::GLOW_BLEND_MODE_SOFTLIGHT; - glow_hdr_bleed_threshold = 1.0; - glow_hdr_bleed_scale = 2.0; - glow_bicubic_upscale = false; - - dof_blur_far_enabled = false; - dof_blur_far_distance = 10; - dof_blur_far_transition = 5; - dof_blur_far_amount = 0.1; - dof_blur_far_quality = VS::ENV_DOF_BLUR_QUALITY_MEDIUM; - - dof_blur_near_enabled = false; - dof_blur_near_distance = 2; - dof_blur_near_transition = 1; - dof_blur_near_amount = 0.1; - dof_blur_near_quality = VS::ENV_DOF_BLUR_QUALITY_MEDIUM; - - adjustments_enabled = false; - adjustments_brightness = 1.0; - adjustments_contrast = 1.0; - adjustments_saturation = 1.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; + Environment() : + bg_mode(VS::ENV_BG_CLEAR_COLOR), + sky_custom_fov(0.0), + bg_energy(1.0), + sky_ambient(0), + camera_feed_id(0), + ambient_energy(1.0), + ambient_sky_contribution(0.0), + canvas_max_layer(0), + ssr_enabled(false), + ssr_max_steps(64), + ssr_fade_in(0.15), + ssr_fade_out(2.0), + ssr_depth_tolerance(0.2), + ssr_roughness(true), + ssao_enabled(false), + ssao_intensity(1.0), + ssao_radius(1.0), + ssao_intensity2(1.0), + ssao_radius2(0.0), + ssao_bias(0.01), + ssao_light_affect(0), + ssao_ao_channel_affect(0), + ssao_quality(VS::ENV_SSAO_QUALITY_LOW), + ssao_bilateral_sharpness(4), + ssao_filter(VS::ENV_SSAO_BLUR_3x3), + glow_enabled(false), + glow_levels((1 << 2) | (1 << 4)), + glow_intensity(0.8), + glow_strength(1.0), + glow_bloom(0.0), + glow_blend_mode(VS::GLOW_BLEND_MODE_SOFTLIGHT), + glow_hdr_bleed_threshold(1.0), + glow_hdr_bleed_scale(2.0), + glow_hdr_luminance_cap(12.0), + glow_bicubic_upscale(false), + tone_mapper(VS::ENV_TONE_MAPPER_LINEAR), + tone_mapper_exposure(1.0), + tone_mapper_exposure_white(1.0), + auto_exposure(false), + auto_exposure_speed(0.5), + auto_exposure_min(0.05), + auto_exposure_max(8), + auto_exposure_grey(0.4), + dof_blur_far_enabled(false), + dof_blur_far_distance(10), + dof_blur_far_transition(5), + dof_blur_far_amount(0.1), + dof_blur_far_quality(VS::ENV_DOF_BLUR_QUALITY_MEDIUM), + dof_blur_near_enabled(false), + dof_blur_near_distance(2), + dof_blur_near_transition(1), + dof_blur_near_amount(0.1), + dof_blur_near_quality(VS::ENV_DOF_BLUR_QUALITY_MEDIUM), + adjustments_enabled(false), + adjustments_brightness(1.0), + adjustments_contrast(1.0), + adjustments_saturation(1.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_end(0), + fog_depth_curve(1), + fog_transmit_enabled(true), + fog_transmit_curve(1), + fog_height_enabled(false), + fog_height_min(10), + fog_height_max(0), + fog_height_curve(1) { } }; @@ -537,14 +540,16 @@ public: virtual void environment_set_background(RID p_env, VS::EnvironmentBG p_bg); virtual void environment_set_sky(RID p_env, RID p_sky); virtual void environment_set_sky_custom_fov(RID p_env, float p_scale); + virtual void environment_set_sky_orientation(RID p_env, const Basis &p_orientation); virtual void environment_set_bg_color(RID p_env, const Color &p_color); virtual void environment_set_bg_energy(RID p_env, float p_energy); virtual void environment_set_canvas_max_layer(RID p_env, int p_max_layer); virtual void environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy = 1.0, float p_sky_contribution = 0.0); + virtual void environment_set_camera_feed_id(RID p_env, int p_camera_feed_id); virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); - virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale); + virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness); @@ -555,7 +560,7 @@ public: virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp); virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount); - virtual void 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); + virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve); virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve); virtual bool is_environment(RID p_env); @@ -573,10 +578,15 @@ public: float light_params[4]; //spot attenuation, spot angle, specular, shadow enabled float light_clamp[4]; float light_shadow_color_contact[4]; - float shadow_matrix1[16]; //up to here for spot and omni, rest is for directional - float shadow_matrix2[16]; - float shadow_matrix3[16]; - float shadow_matrix4[16]; + union { + struct { + float matrix1[16]; //up to here for spot and omni, rest is for directional + float matrix2[16]; + float matrix3[16]; + float matrix4[16]; + }; + float matrix[4 * 16]; + } shadow; float shadow_split_offsets[4]; }; @@ -637,9 +647,9 @@ public: Vector3 bounds; Transform transform_to_data; - GIProbeInstance() { - probe = NULL; - tex_cache = 0; + GIProbeInstance() : + probe(NULL), + tex_cache(0) { } }; @@ -659,8 +669,8 @@ public: SORT_FLAG_SKELETON = 1, SORT_FLAG_INSTANCING = 2, MAX_DIRECTIONAL_LIGHTS = 16, - MAX_LIGHTS = 4096, - MAX_REFLECTIONS = 1024, + DEFAULT_MAX_LIGHTS = 4096, + DEFAULT_MAX_REFLECTIONS = 1024, SORT_KEY_PRIORITY_SHIFT = 56, SORT_KEY_PRIORITY_MASK = 0xFF, @@ -691,6 +701,8 @@ public: }; int max_elements; + int max_lights; + int max_reflections; struct Element { @@ -803,6 +815,8 @@ public: RenderList() { max_elements = DEFAULT_MAX_ELEMENTS; + max_lights = DEFAULT_MAX_LIGHTS; + max_reflections = DEFAULT_MAX_REFLECTIONS; } ~RenderList() { @@ -829,9 +843,9 @@ public: _FORCE_INLINE_ void _add_geometry_with_material(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, RasterizerStorageGLES3::Material *p_material, bool p_depth_pass, bool p_shadow_pass); - 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 _draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy, const Basis &p_sky_orientation); - 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); @@ -845,6 +859,9 @@ public: void _render_mrts(Environment *env, const CameraMatrix &p_cam_projection); void _post_process(Environment *env, const CameraMatrix &p_cam_projection); + void _prepare_depth_texture(); + void _bind_depth_texture(); + 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); virtual bool free(RID p_rid); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 25e7bd0424..95be67a5b7 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -101,6 +101,23 @@ #define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#ifndef GLES_OVER_GL +#define glClearDepth glClearDepthf +#endif + +#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 */ +} +#endif + void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) { #ifdef GLES_OVER_GL @@ -610,6 +627,26 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_ p_flags &= ~VS::TEXTURE_FLAG_MIPMAPS; // no mipies for video } +#ifndef GLES_OVER_GL + switch (p_format) { + case Image::FORMAT_RF: + case Image::FORMAT_RGF: + case Image::FORMAT_RGBF: + case Image::FORMAT_RGBAF: + case Image::FORMAT_RH: + case Image::FORMAT_RGH: + case Image::FORMAT_RGBH: + case Image::FORMAT_RGBAH: { + if (!config.texture_float_linear_supported) { + // disable linear texture filtering when not supported for float format on some devices (issue #24295) + p_flags &= ~VS::TEXTURE_FLAG_FILTER; + } + } break; + default: { + } + } +#endif + Texture *texture = texture_owner.get(p_texture); ERR_FAIL_COND(!texture); texture->width = p_width; @@ -666,14 +703,18 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_ int mipmaps = 0; - while (width != 1 && height != 1) { - glTexImage3D(texture->target, 0, internal_format, width, height, depth, 0, format, type, NULL); + while (width > 0 || height > 0 || (p_type == VS::TEXTURE_TYPE_3D && depth > 0)) { + width = MAX(1, width); + height = MAX(1, height); + depth = MAX(1, depth); + + glTexImage3D(texture->target, mipmaps, internal_format, width, height, depth, 0, format, type, NULL); - width = MAX(1, width / 2); - height = MAX(1, height / 2); + width /= 2; + height /= 2; if (p_type == VS::TEXTURE_TYPE_3D) { - depth = MAX(1, depth / 2); + depth /= 2; } mipmaps++; @@ -712,7 +753,11 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) { texture->images.write[p_layer] = p_image; } - +#ifndef GLES_OVER_GL + if (p_image->is_compressed() && p_image->has_mipmaps() && !p_image->is_size_po2()) { + ERR_PRINTS("Texuture '" + texture->path + "' is compressed, has mipmaps but is not of powerf-of-2 size. This does not work on OpenGL ES 3.0."); + } +#endif Image::Format real_format; Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, srgb); @@ -730,7 +775,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: { @@ -852,8 +897,6 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p int size, ofs; img->get_mipmap_offset_and_size(i, ofs, size); - //print_line("mipmap: "+itos(i)+" size: "+itos(size)+" w: "+itos(mm_w)+", h: "+itos(mm_h)); - if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) { if (texture->compressed) { @@ -892,6 +935,9 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p h = MAX(1, h >> 1); } + // Handle array and 3D textures, as those set their data per layer. + tsize *= MAX(texture->alloc_depth, 1); + info.texture_mem -= texture->total_data_size; texture->total_data_size = tsize; info.texture_mem += texture->total_data_size; @@ -948,7 +994,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: { @@ -1017,6 +1063,132 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) return texture->images[p_layer]; } + // 3D textures and 2D texture arrays need special treatment, as the glGetTexImage reads **the whole** + // texture to host-memory. 3D textures and 2D texture arrays are potentially very big, so reading + // everything just to throw everything but one layer away is A Bad Idea. + // + // Unfortunately, to solve this, the copy shader has to read the data out via a shader and store it + // in a temporary framebuffer. The data from the framebuffer can then be read using glReadPixels. + if (texture->type == VS::TEXTURE_TYPE_2D_ARRAY || texture->type == VS::TEXTURE_TYPE_3D) { + // can't read a layer that doesn't exist + ERR_FAIL_INDEX_V(p_layer, texture->alloc_depth, Ref<Image>()); + + // get some information about the texture + 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; + + // TODO need to decide between RgbaUnorm and RgbaFloat32 for output + 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 more memory at the end, just in case for buggy drivers + PoolVector<uint8_t>::Write wb = data.write(); + + // generate temporary resources + GLuint tmp_fbo; + glGenFramebuffers(1, &tmp_fbo); + + GLuint tmp_color_attachment; + glGenTextures(1, &tmp_color_attachment); + + // now bring the OpenGL context into the correct state + { + glBindFramebuffer(GL_FRAMEBUFFER, tmp_fbo); + + // back color attachment with memory, then set properties + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, tmp_color_attachment); + // TODO support HDR properly + 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); + + // use the color texture as color attachment for this render pass + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tmp_color_attachment, 0); + + // more GL state, wheeeey + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1, 1, 1, 1); + + // use volume tex for reading + glActiveTexture(GL_TEXTURE0); + glBindTexture(texture->target, texture->tex_id); + + glViewport(0, 0, texture->alloc_width, texture->alloc_height); + + // set up copy shader for proper use + shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb); + shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE3D, texture->type == VS::TEXTURE_TYPE_3D); + shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE2DARRAY, texture->type == VS::TEXTURE_TYPE_2D_ARRAY); + shaders.copy.bind(); + + float layer; + if (texture->type == VS::TEXTURE_TYPE_2D_ARRAY) + layer = (float)p_layer; + else + // calculate the normalized z coordinate for the layer + layer = (float)p_layer / (float)texture->alloc_depth; + + shaders.copy.set_uniform(CopyShaderGLES3::LAYER, layer); + + glBindVertexArray(resources.quadie_array); + } + + // clear color attachment, then perform copy + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // read the image into the host buffer + glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); + + // remove temp resources and unset some GL state + { + shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE3D, false); + shaders.copy.set_conditional(CopyShaderGLES3::USE_TEXTURE2DARRAY, false); + shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + glDeleteTextures(1, &tmp_color_attachment); + glDeleteFramebuffers(1, &tmp_fbo); + } + + wb.release(); + + 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); + } + #ifdef GLES_OVER_GL Image::Format real_format; @@ -1029,7 +1201,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(); @@ -1040,14 +1212,9 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - //print_line("GET FORMAT: " + Image::get_format_name(texture->format) + " mipmaps: " + itos(texture->mipmaps)); - for (int i = 0; i < texture->mipmaps; i++) { - int ofs = 0; - if (i > 0) { - ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1); - } + int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, real_format, i); if (texture->compressed) { @@ -1072,7 +1239,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; @@ -1085,17 +1252,84 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) img_format = real_format; } - wb = PoolVector<uint8_t>::Write(); + wb.release(); data.resize(data_size); - Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, img_format, data)); + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1, img_format, data)); 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); + + 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.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb); + shaders.copy.bind(); + + 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.release(); + + 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 } @@ -1207,6 +1441,15 @@ uint32_t RasterizerStorageGLES3::texture_get_texid(RID p_texture) const { return texture->tex_id; } +void RasterizerStorageGLES3::texture_bind(RID p_texture, uint32_t p_texture_no) { + + Texture *texture = texture_owner.getornull(p_texture); + + ERR_FAIL_COND(!texture); + + glActiveTexture(GL_TEXTURE0 + p_texture_no); + glBindTexture(texture->target, texture->tex_id); +} uint32_t RasterizerStorageGLES3::texture_get_width(RID p_texture) const { Texture *texture = texture_owner.get(p_texture); @@ -1275,7 +1518,7 @@ void RasterizerStorageGLES3::texture_debug_usage(List<VS::TextureInfo> *r_info) tinfo.format = t->format; tinfo.width = t->alloc_width; tinfo.height = t->alloc_height; - tinfo.depth = 0; + tinfo.depth = t->alloc_depth; tinfo.bytes = t->total_data_size; r_info->push_back(tinfo); } @@ -1322,7 +1565,7 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_ ERR_FAIL_COND_V(!texture, RID()); ERR_FAIL_COND_V(texture->type != VS::TEXTURE_TYPE_CUBEMAP, RID()); - bool use_float = config.hdr_supported; + bool use_float = config.framebuffer_half_float_supported; if (p_resolution < 0) { p_resolution = texture->width; @@ -1461,6 +1704,17 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_ return texture_owner.make_rid(ctex); } +Size2 RasterizerStorageGLES3::texture_size_with_proxy(RID p_texture) const { + + const Texture *texture = texture_owner.getornull(p_texture); + ERR_FAIL_COND_V(!texture, Size2()); + if (texture->proxy) { + return Size2(texture->proxy->width, texture->proxy->height); + } else { + return Size2(texture->width, texture->height); + } +} + void RasterizerStorageGLES3::texture_set_proxy(RID p_texture, RID p_proxy) { Texture *texture = texture_owner.get(p_texture); @@ -1559,7 +1813,7 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra int array_level = 6; - bool use_float = config.hdr_supported; + bool use_float = config.framebuffer_half_float_supported; GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2; GLenum format = GL_RGBA; @@ -1671,7 +1925,7 @@ void RasterizerStorageGLES3::sky_set_texture(RID p_sky, RID p_panorama, int p_ra int mm_level = mipmaps; - bool use_float = config.hdr_supported; + bool use_float = config.framebuffer_half_float_supported; GLenum internal_format = use_float ? GL_RGBA16F : GL_RGB10_A2; GLenum format = GL_RGBA; @@ -1811,6 +2065,10 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->uniforms.clear(); + if (p_shader->code == String()) { + return; //just invalid, but no error + } + ShaderCompilerGLES3::GeneratedCode gen_code; ShaderCompilerGLES3::IdentifierActions *actions = NULL; @@ -1905,11 +2163,14 @@ 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); - - ERR_FAIL_COND(err != OK); + if (err != OK) { + return; + } p_shader->shader->set_custom_shader_code(p_shader->custom_code_id, gen_code.vertex, gen_code.vertex_global, gen_code.fragment, gen_code.light, gen_code.fragment_global, gen_code.uniforms, gen_code.texture_uniforms, gen_code.defines); @@ -1987,7 +2248,7 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn pi.type = Variant::INT; if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_RANGE) { pi.hint = PROPERTY_HINT_RANGE; - pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]); + pi.hint_string = rtos(u.hint_range[0]) + "," + rtos(u.hint_range[1]) + "," + rtos(u.hint_range[2]); } } break; @@ -2028,6 +2289,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: { @@ -2148,8 +2417,9 @@ Variant RasterizerStorageGLES3::material_get_param_default(RID p_material, const 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); + ShaderLanguage::ShaderNode::Uniform uniform = material->shader->uniforms[p_param]; + Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); } } return Variant(); @@ -2253,27 +2523,27 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy int v = value; GLuint *gui = (GLuint *)data; - gui[0] = v & 1 ? GL_TRUE : GL_FALSE; - gui[1] = v & 2 ? GL_TRUE : GL_FALSE; + gui[0] = (v & 1) ? GL_TRUE : GL_FALSE; + gui[1] = (v & 2) ? GL_TRUE : GL_FALSE; } break; case ShaderLanguage::TYPE_BVEC3: { int v = value; GLuint *gui = (GLuint *)data; - gui[0] = v & 1 ? GL_TRUE : GL_FALSE; - gui[1] = v & 2 ? GL_TRUE : GL_FALSE; - gui[2] = v & 4 ? GL_TRUE : GL_FALSE; + gui[0] = (v & 1) ? GL_TRUE : GL_FALSE; + gui[1] = (v & 2) ? GL_TRUE : GL_FALSE; + gui[2] = (v & 4) ? GL_TRUE : GL_FALSE; } break; case ShaderLanguage::TYPE_BVEC4: { int v = value; GLuint *gui = (GLuint *)data; - gui[0] = v & 1 ? GL_TRUE : GL_FALSE; - gui[1] = v & 2 ? GL_TRUE : GL_FALSE; - gui[2] = v & 4 ? GL_TRUE : GL_FALSE; - gui[3] = v & 8 ? GL_TRUE : GL_FALSE; + gui[0] = (v & 1) ? GL_TRUE : GL_FALSE; + gui[1] = (v & 2) ? GL_TRUE : GL_FALSE; + gui[2] = (v & 4) ? GL_TRUE : GL_FALSE; + gui[3] = (v & 8) ? GL_TRUE : GL_FALSE; } break; case ShaderLanguage::TYPE_INT: { @@ -2493,7 +2763,8 @@ _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataTy gui[14] = v.origin.z; gui[15] = 1; } break; - default: {} + default: { + } } } @@ -2661,7 +2932,8 @@ _FORCE_INLINE_ static void _fill_std140_ubo_value(ShaderLanguage::DataType type, gui[i] = value[i].real; } } break; - default: {} + default: { + } } } @@ -2684,7 +2956,9 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, case ShaderLanguage::TYPE_BVEC3: case ShaderLanguage::TYPE_IVEC3: case ShaderLanguage::TYPE_UVEC3: - case ShaderLanguage::TYPE_VEC3: + case ShaderLanguage::TYPE_VEC3: { + zeromem(data, 12); + } break; case ShaderLanguage::TYPE_BVEC4: case ShaderLanguage::TYPE_IVEC4: case ShaderLanguage::TYPE_UVEC4: @@ -2704,7 +2978,8 @@ _FORCE_INLINE_ static void _fill_std140_ubo_empty(ShaderLanguage::DataType type, zeromem(data, 64); } break; - default: {} + default: { + } } } @@ -2729,7 +3004,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { if (material->shader && material->shader->mode == VS::SHADER_SPATIAL) { if (material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX && - (!material->shader->spatial.uses_alpha || (material->shader->spatial.uses_alpha && material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))) { + (!material->shader->spatial.uses_alpha || material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) { can_cast_shadow = true; } @@ -2750,7 +3025,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { } for (Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.front(); E; E = E->next()) { - E->key()->base_material_changed(); + E->key()->base_changed(false, true); } } } @@ -2786,9 +3061,6 @@ void RasterizerStorageGLES3::_update_material(Material *material) { if (E->get().order < 0) continue; // texture, does not go here - //if (material->shader->mode == VS::SHADER_PARTICLES) { - // print_line("uniform " + String(E->key()) + " order " + itos(E->get().order) + " offset " + itos(material->shader->ubo_offsets[E->get().order])); - //} //regular uniform uint8_t *data = &local_ubo[material->shader->ubo_offsets[E->get().order]]; @@ -2922,8 +3194,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: //must have index and bones, both. { uint32_t bones_weight = VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS; - ERR_EXPLAIN("Array must have both bones and weights in format or none."); - ERR_FAIL_COND((p_format & bones_weight) && (p_format & bones_weight) != bones_weight); + ERR_FAIL_COND_MSG((p_format & bones_weight) && (p_format & bones_weight) != bones_weight, "Array must have both bones and weights in format or none."); } //bool has_morph = p_blend_shapes.size(); @@ -3176,7 +3447,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: glGenBuffers(1, &surface->vertex_id); glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), p_format & VS::ARRAY_FLAG_USE_DYNAMIC_UPDATE ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), (p_format & VS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind if (p_format & VS::ARRAY_FORMAT_INDEX) { @@ -3211,9 +3482,9 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: continue; if (attribs[i].integer) { - glVertexAttribIPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].stride, ((uint8_t *)0) + attribs[i].offset); + glVertexAttribIPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset)); } else { - glVertexAttribPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, ((uint8_t *)0) + attribs[i].offset); + glVertexAttribPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset)); } glEnableVertexAttribArray(attribs[i].index); } @@ -3245,7 +3516,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: if (p_vertex_count < (1 << 16)) { //read 16 bit indices const uint16_t *src_idx = (const uint16_t *)ir.ptr(); - for (int i = 0; i < index_count; i += 6) { + for (int i = 0; i + 5 < index_count; i += 6) { wr[i + 0] = src_idx[i / 2]; wr[i + 1] = src_idx[i / 2 + 1]; @@ -3259,7 +3530,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: //read 16 bit indices const uint32_t *src_idx = (const uint32_t *)ir.ptr(); - for (int i = 0; i < index_count; i += 6) { + for (int i = 0; i + 5 < index_count; i += 6) { wr[i + 0] = src_idx[i / 2]; wr[i + 1] = src_idx[i / 2 + 1]; @@ -3275,7 +3546,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: index_count = p_vertex_count * 2; wf_indices.resize(index_count); PoolVector<uint32_t>::Write wr = wf_indices.write(); - for (int i = 0; i < index_count; i += 6) { + for (int i = 0; i + 5 < index_count; i += 6) { wr[i + 0] = i / 2; wr[i + 1] = i / 2 + 1; @@ -3316,9 +3587,9 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: continue; if (attribs[i].integer) { - glVertexAttribIPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].stride, ((uint8_t *)0) + attribs[i].offset); + glVertexAttribIPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset)); } else { - glVertexAttribPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, ((uint8_t *)0) + attribs[i].offset); + glVertexAttribPointer(attribs[i].index, attribs[i].size, attribs[i].type, attribs[i].normalized, attribs[i].stride, CAST_INT_TO_UCHAR_PTR(attribs[i].offset)); } glEnableVertexAttribArray(attribs[i].index); } @@ -3361,9 +3632,9 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: continue; if (attribs[j].integer) { - glVertexAttribIPointer(attribs[j].index, attribs[j].size, attribs[j].type, attribs[j].stride, ((uint8_t *)0) + attribs[j].offset); + glVertexAttribIPointer(attribs[j].index, attribs[j].size, attribs[j].type, attribs[j].stride, CAST_INT_TO_UCHAR_PTR(attribs[j].offset)); } else { - glVertexAttribPointer(attribs[j].index, attribs[j].size, attribs[j].type, attribs[j].normalized, attribs[j].stride, ((uint8_t *)0) + attribs[j].offset); + glVertexAttribPointer(attribs[j].index, attribs[j].size, attribs[j].type, attribs[j].normalized, attribs[j].stride, CAST_INT_TO_UCHAR_PTR(attribs[j].offset)); } glEnableVertexAttribArray(attribs[j].index); } @@ -3376,7 +3647,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: } mesh->surfaces.push_back(surface); - mesh->instance_change_notify(); + mesh->instance_change_notify(true, true); info.vertex_mem += surface->total_data_size; } @@ -3390,6 +3661,7 @@ void RasterizerStorageGLES3::mesh_set_blend_shape_count(RID p_mesh, int p_amount ERR_FAIL_COND(p_amount < 0); mesh->blend_shape_count = p_amount; + mesh->instance_change_notify(true, false); } int RasterizerStorageGLES3::mesh_get_blend_shape_count(RID p_mesh) const { @@ -3449,7 +3721,7 @@ void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface _material_add_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]); } - mesh->instance_material_change_notify(); + mesh->instance_change_notify(false, true); } RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const { @@ -3485,21 +3757,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; } @@ -3510,23 +3787,29 @@ PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_m Surface *surface = mesh->surfaces[p_surface]; - 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); - { + if (surface->index_array_byte_size > 0) { + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); - PoolVector<uint8_t>::Write w = ret.write(); - copymem(w.ptr(), data, surface->index_array_byte_size); - } +#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 - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + } return ret; } @@ -3568,23 +3851,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; @@ -3633,13 +3919,11 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface) { info.vertex_mem -= surface->total_data_size; - mesh->instance_material_change_notify(); - memdelete(surface); mesh->surfaces.remove(p_surface); - mesh->instance_change_notify(); + mesh->instance_change_notify(true, true); } int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const { @@ -3655,7 +3939,7 @@ void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb ERR_FAIL_COND(!mesh); mesh->custom_aabb = p_aabb; - mesh->instance_change_notify(); + mesh->instance_change_notify(true, false); } AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const { @@ -3671,12 +3955,14 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { Mesh *mesh = mesh_owner.get(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); - if (mesh->custom_aabb != AABB()) + if (mesh->custom_aabb != AABB()) { return mesh->custom_aabb; + } Skeleton *sk = NULL; - if (p_skeleton.is_valid()) + if (p_skeleton.is_valid()) { sk = skeleton_owner.get(p_skeleton); + } AABB aabb; @@ -3715,6 +4001,7 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { mtx.origin.y = texture[base_ofs + 3]; AABB baabb = mtx.xform(skbones[j]); + if (first) { laabb = baabb; first = false; @@ -3862,7 +4149,7 @@ void RasterizerStorageGLES3::mesh_render_blend_shapes(Surface *s, const float *p for (int ti = 0; ti < mtc; ti++) { float weight = p_weights[ti]; - if (weight < 0.001) //not bother with this one + if (weight < 0.00001) //not bother with this one continue; glBindVertexArray(s->blend_shapes[ti].array_id); @@ -3880,44 +4167,44 @@ void RasterizerStorageGLES3::mesh_render_blend_shapes(Surface *s, const float *p case VS::ARRAY_VERTEX: { if (s->format & VS::ARRAY_FLAG_USE_2D_VERTICES) { - glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 2 * 4; } else { - glVertexAttribPointer(i + 8, 3, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i + 8, 3, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 3 * 4; } } break; case VS::ARRAY_NORMAL: { - glVertexAttribPointer(i + 8, 3, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i + 8, 3, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 3 * 4; } break; case VS::ARRAY_TANGENT: { - glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 4 * 4; } break; case VS::ARRAY_COLOR: { - glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 4 * 4; } break; case VS::ARRAY_TEX_UV: { - glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 2 * 4; } break; case VS::ARRAY_TEX_UV2: { - glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i + 8, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 2 * 4; } break; case VS::ARRAY_BONES: { - glVertexAttribIPointer(i + 8, 4, GL_UNSIGNED_INT, stride, ((uint8_t *)0) + ofs); + glVertexAttribIPointer(i + 8, 4, GL_UNSIGNED_INT, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 4 * 4; } break; case VS::ARRAY_WEIGHTS: { - glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i + 8, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 4 * 4; } break; @@ -3950,44 +4237,44 @@ void RasterizerStorageGLES3::mesh_render_blend_shapes(Surface *s, const float *p case VS::ARRAY_VERTEX: { if (s->format & VS::ARRAY_FLAG_USE_2D_VERTICES) { - glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 2 * 4; } else { - glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 3 * 4; } } break; case VS::ARRAY_NORMAL: { - glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i, 3, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 3 * 4; } break; case VS::ARRAY_TANGENT: { - glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 4 * 4; } break; case VS::ARRAY_COLOR: { - glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 4 * 4; } break; case VS::ARRAY_TEX_UV: { - glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 2 * 4; } break; case VS::ARRAY_TEX_UV2: { - glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i, 2, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 2 * 4; } break; case VS::ARRAY_BONES: { - glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, ((uint8_t *)0) + ofs); + glVertexAttribIPointer(i, 4, GL_UNSIGNED_INT, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 4 * 4; } break; case VS::ARRAY_WEIGHTS: { - glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)0) + ofs); + glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, stride, CAST_INT_TO_UCHAR_PTR(ofs)); ofs += 4 * 4; } break; @@ -4057,35 +4344,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; } @@ -4100,14 +4389,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; } @@ -4121,13 +4410,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; } } @@ -4361,7 +4650,6 @@ Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_mu } Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int p_index) const { - MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh); ERR_FAIL_COND_V(!multimesh, Color()); ERR_FAIL_INDEX_V(p_index, multimesh->size, Color()); @@ -4552,7 +4840,7 @@ void RasterizerStorageGLES3::update_dirty_multimeshes() { multimesh->dirty_aabb = false; multimesh->dirty_data = false; - multimesh->instance_change_notify(); + multimesh->instance_change_notify(true, false); multimesh_update_list.remove(multimesh_update_list.first()); } @@ -4663,7 +4951,7 @@ void RasterizerStorageGLES3::immediate_end(RID p_immediate) { im->building = false; - im->instance_change_notify(); + im->instance_change_notify(true, false); } void RasterizerStorageGLES3::immediate_clear(RID p_immediate) { @@ -4672,7 +4960,7 @@ void RasterizerStorageGLES3::immediate_clear(RID p_immediate) { ERR_FAIL_COND(im->building); im->chunks.clear(); - im->instance_change_notify(); + im->instance_change_notify(true, false); } AABB RasterizerStorageGLES3::immediate_get_aabb(RID p_immediate) const { @@ -4687,7 +4975,7 @@ void RasterizerStorageGLES3::immediate_set_material(RID p_immediate, RID p_mater Immediate *im = immediate_owner.get(p_immediate); ERR_FAIL_COND(!im); im->material = p_material; - im->instance_material_change_notify(); + im->instance_change_notify(false, true); } RID RasterizerStorageGLES3::immediate_get_material(RID p_immediate) const { @@ -4893,7 +5181,7 @@ void RasterizerStorageGLES3::update_dirty_skeletons() { } for (Set<RasterizerScene::InstanceBase *>::Element *E = skeleton->instances.front(); E; E = E->next()) { - E->get()->base_changed(); + E->get()->base_changed(true, false); } skeleton_update_list.remove(skeleton_update_list.first()); @@ -4930,6 +5218,7 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type) { light->directional_blend_splits = false; light->directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; light->reverse_cull = false; + light->use_gi = true; light->version = 0; return light_owner.make_rid(light); @@ -4959,8 +5248,10 @@ void RasterizerStorageGLES3::light_set_param(RID p_light, VS::LightParam p_param case VS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } break; + default: { + } } light->param[p_param] = p_value; @@ -4972,7 +5263,7 @@ void RasterizerStorageGLES3::light_set_shadow(RID p_light, bool p_enabled) { light->shadow = p_enabled; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_set_shadow_color(RID p_light, const Color &p_color) { @@ -5005,7 +5296,7 @@ void RasterizerStorageGLES3::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->cull_mask = p_mask; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { @@ -5014,8 +5305,20 @@ 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(true, false); } +void RasterizerStorageGLES3::light_set_use_gi(RID p_light, bool p_enabled) { + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->use_gi = p_enabled; + + light->version++; + light->instance_change_notify(true, false); +} void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) { Light *light = light_owner.getornull(p_light); @@ -5024,7 +5327,7 @@ void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light, VS::LightOm light->omni_shadow_mode = p_mode; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } VS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) { @@ -5042,7 +5345,7 @@ void RasterizerStorageGLES3::light_omni_set_shadow_detail(RID p_light, VS::Light light->omni_shadow_detail = p_detail; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) { @@ -5052,7 +5355,7 @@ void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light, VS:: light->directional_shadow_mode = p_mode; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_directional_set_blend_splits(RID p_light, bool p_enable) { @@ -5062,7 +5365,7 @@ void RasterizerStorageGLES3::light_directional_set_blend_splits(RID p_light, boo light->directional_blend_splits = p_enable; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } bool RasterizerStorageGLES3::light_directional_get_blend_splits(RID p_light) const { @@ -5121,6 +5424,13 @@ Color RasterizerStorageGLES3::light_get_color(RID p_light) { return light->color; } +bool RasterizerStorageGLES3::light_get_use_gi(RID p_light) { + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, false); + + return light->use_gi; +} + bool RasterizerStorageGLES3::light_has_shadow(RID p_light) const { const Light *light = light_owner.getornull(p_light); @@ -5149,21 +5459,19 @@ AABB RasterizerStorageGLES3::light_get_aabb(RID p_light) const { float len = light->param[VS::LIGHT_PARAM_RANGE]; float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len; return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len)); - } break; + }; case VS::LIGHT_OMNI: { float r = light->param[VS::LIGHT_PARAM_RANGE]; return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2); - } break; + }; case VS::LIGHT_DIRECTIONAL: { return AABB(); - } break; - default: {} + }; } ERR_FAIL_V(AABB()); - return AABB(); } /* PROBE API */ @@ -5175,6 +5483,8 @@ RID RasterizerStorageGLES3::reflection_probe_create() { reflection_probe->intensity = 1.0; reflection_probe->interior_ambient = Color(); reflection_probe->interior_ambient_energy = 1.0; + reflection_probe->interior_ambient_probe_contrib = 0.0; + reflection_probe->max_distance = 0; reflection_probe->extents = Vector3(1, 1, 1); reflection_probe->origin_offset = Vector3(0, 0, 0); @@ -5193,7 +5503,7 @@ void RasterizerStorageGLES3::reflection_probe_set_update_mode(RID p_probe, VS::R ERR_FAIL_COND(!reflection_probe); reflection_probe->update_mode = p_mode; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity) { @@ -5234,7 +5544,7 @@ void RasterizerStorageGLES3::reflection_probe_set_max_distance(RID p_probe, floa ERR_FAIL_COND(!reflection_probe); reflection_probe->max_distance = p_distance; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { @@ -5242,7 +5552,7 @@ void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vec ERR_FAIL_COND(!reflection_probe); reflection_probe->extents = p_extents; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { @@ -5250,7 +5560,7 @@ void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, con ERR_FAIL_COND(!reflection_probe); reflection_probe->origin_offset = p_offset; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { @@ -5259,6 +5569,7 @@ void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool ERR_FAIL_COND(!reflection_probe); reflection_probe->interior = p_enable; + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { @@ -5274,7 +5585,7 @@ void RasterizerStorageGLES3::reflection_probe_set_enable_shadows(RID p_probe, bo ERR_FAIL_COND(!reflection_probe); reflection_probe->enable_shadows = p_enable; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { @@ -5282,7 +5593,10 @@ void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_ ERR_FAIL_COND(!reflection_probe); reflection_probe->cull_mask = p_layers; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); +} + +void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution) { } AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const { @@ -5367,7 +5681,7 @@ void RasterizerStorageGLES3::gi_probe_set_bounds(RID p_probe, const AABB &p_boun gip->bounds = p_bounds; gip->version++; - gip->instance_change_notify(); + gip->instance_change_notify(true, false); } AABB RasterizerStorageGLES3::gi_probe_get_bounds(RID p_probe) const { @@ -5384,7 +5698,7 @@ void RasterizerStorageGLES3::gi_probe_set_cell_size(RID p_probe, float p_size) { gip->cell_size = p_size; gip->version++; - gip->instance_change_notify(); + gip->instance_change_notify(true, false); } float RasterizerStorageGLES3::gi_probe_get_cell_size(RID p_probe) const { @@ -5417,7 +5731,7 @@ void RasterizerStorageGLES3::gi_probe_set_dynamic_data(RID p_probe, const PoolVe gip->dynamic_data = p_data; gip->version++; - gip->instance_change_notify(); + gip->instance_change_notify(true, false); } PoolVector<int> RasterizerStorageGLES3::gi_probe_get_dynamic_data(RID p_probe) const { @@ -5649,7 +5963,7 @@ void RasterizerStorageGLES3::lightmap_capture_set_bounds(RID p_capture, const AA LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND(!capture); capture->bounds = p_bounds; - capture->instance_change_notify(); + capture->instance_change_notify(true, false); } AABB RasterizerStorageGLES3::lightmap_capture_get_bounds(RID p_capture) const { @@ -5670,7 +5984,7 @@ void RasterizerStorageGLES3::lightmap_capture_set_octree(RID p_capture, const Po PoolVector<uint8_t>::Read r = p_octree.read(); copymem(w.ptr(), r.ptr(), p_octree.size()); } - capture->instance_change_notify(); + capture->instance_change_notify(true, false); } PoolVector<uint8_t> RasterizerStorageGLES3::lightmap_capture_get_octree(RID p_capture) const { @@ -5748,10 +6062,7 @@ void RasterizerStorageGLES3::particles_set_emitting(RID p_particles, bool p_emit Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND(!particles); - if (p_emitting != particles->emitting) { - // Restart is overridden by set_emitting - particles->restart_request = false; - } + particles->emitting = p_emitting; } @@ -5783,9 +6094,9 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[i]); glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_STATIC_DRAW); - for (int i = 0; i < 6; i++) { - glEnableVertexAttribArray(i); - glVertexAttribPointer(i, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (i * 16)); + for (int j = 0; j < 6; j++) { + glEnableVertexAttribArray(j); + glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, CAST_INT_TO_UCHAR_PTR(j * 16)); } } @@ -5799,7 +6110,7 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) for (int j = 0; j < 6; j++) { glEnableVertexAttribArray(j); - glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (j * 16)); + glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, CAST_INT_TO_UCHAR_PTR(j * 16)); } particles->particle_valid_histories[i] = false; } @@ -5877,7 +6188,7 @@ void RasterizerStorageGLES3::_particles_update_histories(Particles *particles) { for (int j = 0; j < 6; j++) { glEnableVertexAttribArray(j); - glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, ((uint8_t *)0) + (j * 16)); + glVertexAttribPointer(j, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 4 * 6, CAST_INT_TO_UCHAR_PTR(j * 16)); } particles->particle_valid_histories[i] = false; @@ -5893,7 +6204,7 @@ void RasterizerStorageGLES3::particles_set_custom_aabb(RID p_particles, const AA ERR_FAIL_COND(!particles); particles->custom_aabb = p_aabb; _particles_update_histories(particles); - particles->instance_change_notify(); + particles->instance_change_notify(true, false); } void RasterizerStorageGLES3::particles_set_speed_scale(RID p_particles, float p_scale) { @@ -5983,9 +6294,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(); @@ -6002,7 +6325,13 @@ AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { aabb.expand_to(pos); } +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + r.release(); + vector = PoolVector<uint8_t>(); +#else glUnmapBuffer(GL_ARRAY_BUFFER); +#endif + glBindBuffer(GL_ARRAY_BUFFER, 0); float longest_axis = 0; @@ -6131,7 +6460,6 @@ void RasterizerStorageGLES3::update_particles() { Particles *particles = particle_update_list.first()->self(); if (particles->restart_request) { - particles->emitting = true; //restart from zero particles->prev_ticks = 0; particles->phase = 0; particles->prev_phase = 0; @@ -6301,12 +6629,19 @@ void RasterizerStorageGLES3::update_particles() { particles->particle_valid_histories[0] = true; } - particles->instance_change_notify(); //make sure shadows are updated + particles->instance_change_notify(true, false); //make sure shadows are updated } glDisable(GL_RASTERIZER_DISCARD); } +bool RasterizerStorageGLES3::particles_is_inactive(RID p_particles) const { + + const Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND_V(!particles, false); + return !particles->emitting && particles->inactive; +} + //////// void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { @@ -6362,9 +6697,7 @@ void RasterizerStorageGLES3::instance_add_dependency(RID p_base, RasterizerScene ERR_FAIL_COND(!inst); } break; default: { - if (!inst) { - ERR_FAIL(); - } + ERR_FAIL(); } } @@ -6409,15 +6742,10 @@ void RasterizerStorageGLES3::instance_remove_dependency(RID p_base, RasterizerSc ERR_FAIL_COND(!inst); } break; default: { - - if (!inst) { - ERR_FAIL(); - } + ERR_FAIL(); } } - ERR_FAIL_COND(!inst); - inst->instance_list.remove(&p_instance->dependency_item); } @@ -6474,6 +6802,24 @@ void RasterizerStorageGLES3::_render_target_clear(RenderTarget *rt) { glDeleteTextures(1, &rt->exposure.color); rt->exposure.fbo = 0; } + + if (rt->external.fbo != 0) { + // free this + glDeleteFramebuffers(1, &rt->external.fbo); + + // clean up our texture + Texture *t = texture_owner.get(rt->external.texture); + t->alloc_height = 0; + t->alloc_width = 0; + t->width = 0; + t->height = 0; + t->active = false; + texture_owner.free(rt->external.texture); + memdelete(t); + + rt->external.fbo = 0; + } + Texture *tex = texture_owner.get(rt->texture); tex->alloc_height = 0; tex->alloc_width = 0; @@ -6513,7 +6859,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { GLuint color_type; Image::Format image_format; - bool hdr = rt->flags[RENDER_TARGET_HDR] && config.hdr_supported; + bool hdr = rt->flags[RENDER_TARGET_HDR] && config.framebuffer_half_float_supported; //hdr = false; if (!hdr || rt->flags[RENDER_TARGET_NO_3D]) { @@ -6549,8 +6895,9 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glGenTextures(1, &rt->depth); glBindTexture(GL_TEXTURE_2D, rt->depth); - glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH24_STENCIL8, rt->width, rt->height, 0, - GL_DEPTH_STENCIL, GL_UNSIGNED_INT_24_8, NULL); + glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, rt->width, rt->height, 0, + GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); @@ -6617,9 +6964,9 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glGenRenderbuffers(1, &rt->buffers.depth); glBindRenderbuffer(GL_RENDERBUFFER, rt->buffers.depth); if (msaa == 0) - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, rt->width, rt->height); + glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT24, rt->width, rt->height); else - glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_DEPTH24_STENCIL8, rt->width, rt->height); + glRenderbufferStorageMultisample(GL_RENDERBUFFER, msaa, GL_DEPTH_COMPONENT24, rt->width, rt->height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->buffers.depth); @@ -6767,7 +7114,14 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glGenTextures(1, &rt->exposure.color); glBindTexture(GL_TEXTURE_2D, rt->exposure.color); - glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 1, 1, 0, GL_RED, GL_FLOAT, NULL); + if (config.framebuffer_float_supported) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_R32F, 1, 1, 0, GL_RED, GL_FLOAT, NULL); + } else if (config.framebuffer_half_float_supported) { + glTexImage2D(GL_TEXTURE_2D, 0, GL_R16F, 1, 1, 0, GL_RED, GL_HALF_FLOAT, NULL); + } else { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB10_A2, 1, 1, 0, GL_RGBA, GL_UNSIGNED_INT_2_10_10_10_REV, NULL); + } + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, rt->exposure.color, 0); status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -6825,7 +7179,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); } @@ -6852,7 +7206,8 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glViewport(0, 0, rt->effects.mip_maps[i].sizes[j].width, rt->effects.mip_maps[i].sizes[j].height); glClearBufferfv(GL_COLOR, 0, zero); if (used_depth) { - glClearBufferfi(GL_DEPTH_STENCIL, 0, 1.0, 0); + glClearDepth(1.0); + glClear(GL_DEPTH_BUFFER_BIT); } } @@ -6875,6 +7230,7 @@ RID RasterizerStorageGLES3::render_target_create() { Texture *t = memnew(Texture); + t->type = VS::TEXTURE_TYPE_2D; t->flags = 0; t->width = 0; t->height = 0; @@ -6900,6 +7256,10 @@ RID RasterizerStorageGLES3::render_target_create() { return render_target_owner.make_rid(rt); } +void RasterizerStorageGLES3::render_target_set_position(RID p_render_target, int p_x, int p_y) { + //only used in GLES2 +} + void RasterizerStorageGLES3::render_target_set_size(RID p_render_target, int p_width, int p_height) { RenderTarget *rt = render_target_owner.getornull(p_render_target); @@ -6919,7 +7279,99 @@ RID RasterizerStorageGLES3::render_target_get_texture(RID p_render_target) const RenderTarget *rt = render_target_owner.getornull(p_render_target); ERR_FAIL_COND_V(!rt, RID()); - return rt->texture; + if (rt->external.fbo == 0) { + return rt->texture; + } else { + return rt->external.texture; + } +} + +void RasterizerStorageGLES3::render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id) { + RenderTarget *rt = render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + if (p_texture_id == 0) { + if (rt->external.fbo != 0) { + // free this + glDeleteFramebuffers(1, &rt->external.fbo); + + // clean up our texture + Texture *t = texture_owner.get(rt->external.texture); + t->alloc_height = 0; + t->alloc_width = 0; + t->width = 0; + t->height = 0; + t->active = false; + texture_owner.free(rt->external.texture); + memdelete(t); + + rt->external.fbo = 0; + } + } else { + Texture *t; + + if (rt->external.fbo == 0) { + // create our fbo + glGenFramebuffers(1, &rt->external.fbo); + glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); + + // allocate a texture + t = memnew(Texture); + + t->type = VS::TEXTURE_TYPE_2D; + t->flags = 0; + t->width = 0; + t->height = 0; + t->alloc_height = 0; + t->alloc_width = 0; + t->format = Image::FORMAT_RGBA8; + t->target = GL_TEXTURE_2D; + t->gl_format_cache = 0; + t->gl_internal_format_cache = 0; + t->gl_type_cache = 0; + t->data_size = 0; + t->compressed = false; + t->srgb = false; + t->total_data_size = 0; + t->ignore_mipmaps = false; + t->mipmaps = 1; + t->active = true; + t->tex_id = 0; + t->render_target = rt; + + rt->external.texture = texture_owner.make_rid(t); + } else { + // bind our frame buffer + glBindFramebuffer(GL_FRAMEBUFFER, rt->external.fbo); + + // find our texture + t = texture_owner.get(rt->external.texture); + } + + // set our texture + t->tex_id = p_texture_id; + + // size shouldn't be different + t->width = rt->width; + t->height = rt->height; + t->alloc_height = rt->width; + t->alloc_width = rt->height; + + // is there a point to setting the internal formats? we don't know them.. + + // set our texture as the destination for our framebuffer + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, p_texture_id, 0); + + // check status and unbind + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); + + if (status != GL_FRAMEBUFFER_COMPLETE) { + printf("framebuffer fail, status: %x\n", status); + } + + ERR_FAIL_COND(status != GL_FRAMEBUFFER_COMPLETE); + } } void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value) { @@ -6939,7 +7391,8 @@ void RasterizerStorageGLES3::render_target_set_flag(RID p_render_target, RenderT _render_target_allocate(rt); } break; - default: {} + default: { + } } } bool RasterizerStorageGLES3::render_target_was_used(RID p_render_target) { @@ -7200,7 +7653,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) { // delete the texture Shader *shader = shader_owner.get(p_rid); - if (shader->shader) + if (shader->shader && shader->custom_code_id) shader->shader->free_custom_shader(shader->custom_code_id); if (shader->dirty_list.in_list()) @@ -7351,7 +7804,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)) { @@ -7359,7 +7812,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)) { @@ -7521,15 +7974,21 @@ void RasterizerStorageGLES3::initialize() { config.latc_supported = config.extensions.has("GL_EXT_texture_compression_latc"); config.bptc_supported = config.extensions.has("GL_ARB_texture_compression_bptc"); #ifdef GLES_OVER_GL - config.hdr_supported = true; config.etc2_supported = false; config.s3tc_supported = true; config.rgtc_supported = true; //RGTC - core since OpenGL version 3.0 + config.texture_float_linear_supported = true; + config.framebuffer_float_supported = true; + config.framebuffer_half_float_supported = true; + #else config.etc2_supported = true; - config.hdr_supported = false; config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_dxt1") || config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); - config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc"); + config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc") || config.extensions.has("EXT_texture_compression_rgtc"); + config.texture_float_linear_supported = config.extensions.has("GL_OES_texture_float_linear"); + config.framebuffer_float_supported = config.extensions.has("GL_EXT_color_buffer_float"); + config.framebuffer_half_float_supported = config.extensions.has("GL_EXT_color_buffer_half_float") || config.framebuffer_float_supported; + #endif config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc"); @@ -7609,16 +8068,20 @@ void RasterizerStorageGLES3::initialize() { glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0); glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0); + + glGenTextures(1, &resources.white_tex_array); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D_ARRAY, resources.white_tex_array); + glTexImage3D(GL_TEXTURE_2D_ARRAY, 0, GL_RGB, 8, 8, 1, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + glTexSubImage3D(GL_TEXTURE_2D_ARRAY, 0, 0, 0, 0, 8, 8, 1, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata); + glGenerateMipmap(GL_TEXTURE_2D_ARRAY); + glBindTexture(GL_TEXTURE_2D, 0); } glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); -#ifdef GLES_OVER_GL - config.use_rgba_2d_shadows = false; -#else - config.use_rgba_2d_shadows = true; -#endif + config.use_rgba_2d_shadows = !config.framebuffer_float_supported; //generic quadie for copying @@ -7657,7 +8120,7 @@ void RasterizerStorageGLES3::initialize() { glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); glEnableVertexAttribArray(0); - glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, ((uint8_t *)NULL) + 8); + glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, CAST_INT_TO_UCHAR_PTR(8)); glEnableVertexAttribArray(4); glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind @@ -7668,6 +8131,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]); @@ -7681,7 +8146,7 @@ void RasterizerStorageGLES3::initialize() { } shaders.cubemap_filter.init(); - bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx.mobile"); + bool ggx_hq = GLOBAL_GET("rendering/quality/reflections/high_quality_ggx"); shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES3::LOW_QUALITY, !ggx_hq); shaders.particles.init(); @@ -7700,8 +8165,8 @@ void RasterizerStorageGLES3::initialize() { String renderer = (const char *)glGetString(GL_RENDERER); - config.no_depth_prepass = !bool(GLOBAL_GET("rendering/quality/depth_prepass/enable")); - if (!config.no_depth_prepass) { + config.use_depth_prepass = bool(GLOBAL_GET("rendering/quality/depth_prepass/enable")); + if (config.use_depth_prepass) { String vendors = GLOBAL_GET("rendering/quality/depth_prepass/disable_for_vendors"); Vector<String> vendor_match = vendors.split(","); @@ -7711,7 +8176,7 @@ void RasterizerStorageGLES3::initialize() { continue; if (renderer.findn(v) != -1) { - config.no_depth_prepass = true; + config.use_depth_prepass = false; } } } diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 0bd9c22be5..84632308b4 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -43,6 +43,11 @@ #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); +#endif + class RasterizerCanvasGLES3; class RasterizerSceneGLES3; @@ -77,10 +82,12 @@ public: bool etc2_supported; bool pvrtc_supported; - bool hdr_supported; - bool srgb_decode_supported; + bool texture_float_linear_supported; + bool framebuffer_float_supported; + bool framebuffer_half_float_supported; + bool use_rgba_2d_shadows; float anisotropic_level; @@ -96,7 +103,7 @@ public: bool keep_original_textures; - bool no_depth_prepass; + bool use_depth_prepass; bool force_vertex_shading; } config; @@ -125,6 +132,7 @@ public: GLuint aniso_tex; GLuint white_tex_3d; + GLuint white_tex_array; GLuint quadie; GLuint quadie_array; @@ -175,22 +183,12 @@ public: SelfList<RasterizerScene::InstanceBase>::List instance_list; - _FORCE_INLINE_ void instance_change_notify() { + _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); while (instances) { - instances->self()->base_changed(); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_material_change_notify() { - - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - - instances->self()->base_material_changed(); + instances->self()->base_changed(p_aabb, p_materials); instances = instances->next(); } } @@ -289,29 +287,32 @@ public: VisualServer::TextureDetectCallback detect_normal; void *detect_normal_ud; - Texture() { - - using_srgb = false; - stored_cube_sides = 0; - ignore_mipmaps = false; - render_target = NULL; - flags = width = height = 0; - tex_id = 0; - data_size = 0; - format = Image::FORMAT_L8; - active = false; - compressed = false; - total_data_size = 0; - target = GL_TEXTURE_2D; - mipmaps = 0; - detect_3d = NULL; - detect_3d_ud = NULL; - detect_srgb = NULL; - detect_srgb_ud = NULL; - detect_normal = NULL; - detect_normal_ud = NULL; - proxy = NULL; - redraw_if_visible = false; + Texture() : + proxy(NULL), + flags(0), + width(0), + height(0), + format(Image::FORMAT_L8), + type(VS::TEXTURE_TYPE_2D), + target(GL_TEXTURE_2D), + data_size(0), + compressed(false), + srgb(false), + total_data_size(0), + ignore_mipmaps(false), + mipmaps(0), + active(false), + tex_id(0), + using_srgb(false), + redraw_if_visible(false), + stored_cube_sides(0), + render_target(NULL), + detect_3d(NULL), + detect_3d_ud(NULL), + detect_srgb(NULL), + detect_srgb_ud(NULL), + detect_normal(NULL), + detect_normal_ud(NULL) { } _ALWAYS_INLINE_ Texture *get_ptr() { @@ -357,6 +358,7 @@ public: virtual uint32_t texture_get_height(RID p_texture) const; virtual uint32_t texture_get_depth(RID p_texture) const; virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth); + virtual void texture_bind(RID p_texture, uint32_t p_texture_no); virtual void texture_set_path(RID p_texture, const String &p_path); virtual String texture_get_path(RID p_texture) const; @@ -374,6 +376,8 @@ public: virtual void texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata); virtual void texture_set_proxy(RID p_texture, RID p_proxy); + virtual Size2 texture_size_with_proxy(RID p_texture) const; + virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable); /* SKY API */ @@ -443,6 +447,7 @@ public: }; int light_mode; + bool uses_screen_texture; bool uses_screen_uv; bool uses_time; @@ -556,16 +561,16 @@ public: bool is_animated_cache; Material() : + shader(NULL), + ubo_id(0), + ubo_size(0), list(this), - dirty_list(this) { - can_cast_shadow_cache = false; - is_animated_cache = false; - shader = NULL; - line_width = 1.0; - ubo_id = 0; - ubo_size = 0; - last_pass = 0; - render_priority = 0; + dirty_list(this), + line_width(1.0), + render_priority(0), + last_pass(0), + can_cast_shadow_cache(false), + is_animated_cache(false) { } }; @@ -658,40 +663,37 @@ public: bool active; virtual void material_changed_notify() { - mesh->instance_material_change_notify(); + mesh->instance_change_notify(false, true); mesh->update_multimeshes(); } int total_data_size; - Surface() { - - array_byte_size = 0; - index_array_byte_size = 0; - mesh = NULL; - format = 0; - array_id = 0; - vertex_id = 0; - index_id = 0; - array_len = 0; + Surface() : + mesh(NULL), + format(0), + array_id(0), + vertex_id(0), + index_id(0), + index_wireframe_id(0), + array_wireframe_id(0), + instancing_array_wireframe_id(0), + index_wireframe_len(0), + array_len(0), + index_array_len(0), + array_byte_size(0), + index_array_byte_size(0), + primitive(VS::PRIMITIVE_POINTS), + active(false), + total_data_size(0) { type = GEOMETRY_SURFACE; - primitive = VS::PRIMITIVE_POINTS; - index_array_len = 0; - active = false; - - total_data_size = 0; - - index_wireframe_id = 0; - array_wireframe_id = 0; - instancing_array_wireframe_id = 0; - index_wireframe_len = 0; } ~Surface() { } }; - class MultiMesh; + struct MultiMesh; struct Mesh : public GeometryOwner { @@ -706,16 +708,16 @@ public: SelfList<MultiMesh> *mm = multimeshes.first(); while (mm) { - mm->self()->instance_material_change_notify(); + mm->self()->instance_change_notify(false, true); mm = mm->next(); } } - Mesh() { - blend_shape_mode = VS::BLEND_SHAPE_MODE_NORMALIZED; - blend_shape_count = 0; - last_pass = 0; - active = false; + Mesh() : + active(false), + blend_shape_count(0), + blend_shape_mode(VS::BLEND_SHAPE_MODE_NORMALIZED), + last_pass(0) { } }; @@ -783,19 +785,19 @@ public: bool dirty_data; MultiMesh() : + size(0), + transform_format(VS::MULTIMESH_TRANSFORM_2D), + color_format(VS::MULTIMESH_COLOR_NONE), + custom_data_format(VS::MULTIMESH_CUSTOM_DATA_NONE), update_list(this), - mesh_list(this) { - dirty_aabb = true; - dirty_data = true; - xform_floats = 0; - color_floats = 0; - custom_data_floats = 0; - visible_instances = -1; - size = 0; - buffer = 0; - transform_format = VS::MULTIMESH_TRANSFORM_2D; - color_format = VS::MULTIMESH_COLOR_NONE; - custom_data_format = VS::MULTIMESH_CUSTOM_DATA_NONE; + mesh_list(this), + buffer(0), + visible_instances(-1), + xform_floats(0), + color_floats(0), + custom_data_floats(0), + dirty_aabb(true), + dirty_data(true) { } }; @@ -814,7 +816,7 @@ public: virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform); virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform); virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color); - virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color); + virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data); virtual RID multimesh_get_mesh(RID p_multimesh) const; @@ -892,11 +894,10 @@ public: Transform2D base_transform_2d; Skeleton() : + use_2d(false), + size(0), + texture(0), update_list(this) { - size = 0; - - use_2d = false; - texture = 0; } }; @@ -927,6 +928,7 @@ public: bool shadow; bool negative; bool reverse_cull; + bool use_gi; uint32_t cull_mask; VS::LightOmniShadowMode omni_shadow_mode; VS::LightOmniShadowDetail omni_shadow_detail; @@ -948,6 +950,7 @@ public: virtual void light_set_negative(RID p_light, bool p_enable); virtual void light_set_cull_mask(RID p_light, uint32_t p_mask); virtual void light_set_reverse_cull_face_mode(RID p_light, bool p_enabled); + virtual void light_set_use_gi(RID p_light, bool p_enabled); virtual void light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode); virtual void light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail); @@ -967,6 +970,7 @@ public: virtual VS::LightType light_get_type(RID p_light) const; virtual float light_get_param(RID p_light, VS::LightParam p_param); virtual Color light_get_color(RID p_light); + virtual bool light_get_use_gi(RID p_light); virtual AABB light_get_aabb(RID p_light) const; virtual uint64_t light_get_version(RID p_light) const; @@ -1005,6 +1009,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; @@ -1176,37 +1181,31 @@ public: Transform emission_transform; Particles() : - particle_element(this) { - cycle_number = 0; - emitting = false; - one_shot = false; - amount = 0; - lifetime = 1.0; - pre_process_time = 0.0; - explosiveness = 0.0; - randomness = 0.0; - use_local_coords = true; - fixed_fps = 0; - fractional_delta = false; - frame_remainder = 0; - histories_enabled = false; - speed_scale = 1.0; - random_seed = 0; - - restart_request = false; - - custom_aabb = AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8)); - - draw_order = VS::PARTICLES_DRAW_ORDER_INDEX; + inactive(true), + inactive_time(0.0), + emitting(false), + one_shot(false), + amount(0), + lifetime(1.0), + pre_process_time(0.0), + explosiveness(0.0), + randomness(0.0), + restart_request(false), + custom_aabb(AABB(Vector3(-4, -4, -4), Vector3(8, 8, 8))), + use_local_coords(true), + draw_order(VS::PARTICLES_DRAW_ORDER_INDEX), + histories_enabled(false), + particle_element(this), + prev_ticks(0), + random_seed(0), + cycle_number(0), + speed_scale(1.0), + fixed_fps(0), + fractional_delta(false), + frame_remainder(0), + clear(true) { particle_buffers[0] = 0; particle_buffers[1] = 0; - - prev_ticks = 0; - - clear = true; - inactive = true; - inactive_time = 0.0; - glGenBuffers(2, particle_buffers); glGenVertexArrays(2, particle_vaos); } @@ -1263,6 +1262,8 @@ public: virtual int particles_get_draw_passes(RID p_particles) const; virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const; + virtual bool particles_is_inactive(RID p_particles) const; + /* INSTANCE */ virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); @@ -1309,9 +1310,9 @@ public: GLuint color; int levels; - MipMaps() { - color = 0; - levels = 0; + MipMaps() : + color(0), + levels(0) { } }; @@ -1326,10 +1327,10 @@ public: Vector<GLuint> depth_mipmap_fbos; //fbos for depth mipmapsla ver - SSAO() { + SSAO() : + linear_depth(0) { blur_fbo[0] = 0; blur_fbo[1] = 0; - linear_depth = 0; } } ssao; @@ -1341,9 +1342,19 @@ public: GLuint fbo; GLuint color; - Exposure() { fbo = 0; } + Exposure() : + fbo(0) {} } exposure; + // External FBO to render our final result to (mostly used for ARVR) + struct External { + GLuint fbo; + RID texture; + + External() : + fbo(0) {} + } external; + uint64_t last_exposure_tick; int width, height; @@ -1355,26 +1366,23 @@ public: RID texture; - RenderTarget() { - - msaa = VS::VIEWPORT_MSAA_DISABLED; - width = 0; - height = 0; - depth = 0; - fbo = 0; + RenderTarget() : + fbo(0), + depth(0), + last_exposure_tick(0), + width(0), + height(0), + used_in_frame(false), + msaa(VS::VIEWPORT_MSAA_DISABLED) { exposure.fbo = 0; buffers.fbo = 0; - used_in_frame = false; - + external.fbo = 0; for (int i = 0; i < RENDER_TARGET_FLAG_MAX; i++) { flags[i] = false; } flags[RENDER_TARGET_HDR] = true; - buffers.active = false; buffers.effects_active = false; - - last_exposure_tick = 0; } }; @@ -1384,8 +1392,10 @@ public: void _render_target_allocate(RenderTarget *rt); virtual RID render_target_create(); + virtual void render_target_set_position(RID p_render_target, int p_x, int p_y); virtual void render_target_set_size(RID p_render_target, int p_width, int p_height); virtual RID render_target_get_texture(RID p_render_target) const; + virtual void render_target_set_external_texture(RID p_render_target, unsigned int p_texture_id); virtual void render_target_set_flag(RID p_render_target, RenderTargetFlags p_flag, bool p_value); virtual bool render_target_was_used(RID p_render_target); diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 350107de69..7499962da3 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -79,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; } @@ -112,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; } @@ -121,8 +133,7 @@ static String _interpstr(SL::DataInterpolation p_interp) { switch (p_interp) { case SL::INTERPOLATION_FLAT: return "flat "; - case SL::INTERPOLATION_NO_PERSPECTIVE: return "noperspective "; - case SL::INTERPOLATION_SMOOTH: return "smooth "; + case SL::INTERPOLATION_SMOOTH: return ""; } return ""; } @@ -155,15 +166,17 @@ static String _opstr(SL::Operator p_op) { static String _mkid(const String &p_id) { - return "m_" + p_id; + String id = "m_" + p_id; + return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl } static String f2sp0(float p_float) { - if (int(p_float) == p_float) - return itos(p_float) + ".0"; - else - return rtoss(p_float); + String num = rtoss(p_float); + if (num.find(".") == -1 && num.find("e") == -1) { + num += ".0"; + } + return num; } static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { @@ -216,7 +229,7 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNo text += ")"; return text; } break; - case SL::TYPE_FLOAT: return f2sp0(p_values[0].real) + "f"; + case SL::TYPE_FLOAT: return f2sp0(p_values[0].real); case SL::TYPE_VEC2: case SL::TYPE_VEC3: case SL::TYPE_VEC4: { @@ -360,7 +373,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener ucode = "uniform "; } - ucode += _prestr(E->get().precission); + ucode += _prestr(E->get().precision); ucode += _typestr(E->get().type); ucode += " " + _mkid(E->key()); ucode += ";\n"; @@ -451,19 +464,38 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener String vcode; String interp_mode = _interpstr(E->get().interpolation); - vcode += _prestr(E->get().precission); + vcode += _prestr(E->get().precision); vcode += _typestr(E->get().type); vcode += " " + _mkid(E->key()); + if (E->get().array_size > 0) { + vcode += "["; + vcode += itos(E->get().array_size); + vcode += "]"; + } vcode += ";\n"; r_gen_code.vertex_global += interp_mode + "out " + vcode; r_gen_code.fragment_global += interp_mode + "in " + vcode; } + for (Map<StringName, SL::ShaderNode::Constant>::Element *E = pnode->constants.front(); E; E = E->next()) { + String gcode; + gcode += "const "; + gcode += _prestr(E->get().precision); + gcode += _typestr(E->get().type); + gcode += " " + _mkid(E->key()); + gcode += "="; + gcode += _dump_node_code(E->get().initializer, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + gcode += ";\n"; + r_gen_code.vertex_global += gcode; + r_gen_code.fragment_global += gcode; + } + Map<StringName, String> function_code; //code for functions for (int i = 0; i < pnode->functions.size(); i++) { SL::FunctionNode *fnode = pnode->functions[i].function; + current_func_name = fnode->name; function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } @@ -528,7 +560,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener case SL::Node::TYPE_VARIABLE_DECLARATION: { SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node; - String declaration = _prestr(vdnode->precision) + _typestr(vdnode->datatype); + String declaration; + if (vdnode->is_const) { + declaration += "const "; + } + declaration += _prestr(vdnode->precision); + declaration += _typestr(vdnode->datatype); for (int i = 0; i < vdnode->declarations.size(); i++) { if (i > 0) { declaration += ","; @@ -580,6 +617,93 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } } break; + case SL::Node::TYPE_ARRAY_DECLARATION: { + + SL::ArrayDeclarationNode *adnode = (SL::ArrayDeclarationNode *)p_node; + + String declaration; + if (adnode->is_const) { + declaration += "const "; + } + declaration += _prestr(adnode->precision); + declaration += _typestr(adnode->datatype); + for (int i = 0; i < adnode->declarations.size(); i++) { + if (i > 0) { + declaration += ","; + } else { + declaration += " "; + } + declaration += _mkid(adnode->declarations[i].name); + declaration += "["; + declaration += itos(adnode->declarations[i].size); + declaration += "]"; + int sz = adnode->declarations[i].initializer.size(); + if (sz > 0) { + declaration += "="; + declaration += _typestr(adnode->datatype); + declaration += "["; + declaration += itos(sz); + declaration += "]"; + declaration += "("; + for (int j = 0; j < sz; j++) { + declaration += _dump_node_code(adnode->declarations[i].initializer[j], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + if (j != sz - 1) { + declaration += ", "; + } + } + declaration += ")"; + } + } + + code += declaration; + } break; + case SL::Node::TYPE_ARRAY: { + SL::ArrayNode *anode = (SL::ArrayNode *)p_node; + + if (p_assigning && p_actions.write_flag_pointers.has(anode->name)) { + *p_actions.write_flag_pointers[anode->name] = true; + } + + if (p_default_actions.usage_defines.has(anode->name) && !used_name_defines.has(anode->name)) { + String define = p_default_actions.usage_defines[anode->name]; + if (define.begins_with("@")) { + define = p_default_actions.usage_defines[define.substr(1, define.length())]; + } + r_gen_code.defines.push_back(define.utf8()); + used_name_defines.insert(anode->name); + } + + if (p_actions.usage_flag_pointers.has(anode->name) && !used_flag_pointers.has(anode->name)) { + *p_actions.usage_flag_pointers[anode->name] = true; + used_flag_pointers.insert(anode->name); + } + + if (p_default_actions.renames.has(anode->name)) + code = p_default_actions.renames[anode->name]; + else + code = _mkid(anode->name); + + if (anode->call_expression != NULL) { + code += "."; + code += _dump_node_code(anode->call_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + } + + if (anode->index_expression != NULL) { + code += "["; + code += _dump_node_code(anode->index_expression, p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += "]"; + } + + if (anode->name == time_name) { + if (current_func_name == vertex_name) { + r_gen_code.uses_vertex_time = true; + } + if (current_func_name == fragment_name || current_func_name == light_name) { + r_gen_code.uses_fragment_time = true; + } + } + + } break; case SL::Node::TYPE_CONSTANT: { SL::ConstantNode *cnode = (SL::ConstantNode *)p_node; return get_constant_text(cnode->datatype, cnode->values); @@ -653,11 +777,13 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } break; case SL::OP_SELECT_IF: { + code += "("; code += _dump_node_code(onode->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += "?"; code += _dump_node_code(onode->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); code += ":"; code += _dump_node_code(onode->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); + code += ")"; } break; @@ -680,6 +806,20 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener code += _mktab(p_level) + "else\n"; code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } + } else if (cfnode->flow_op == SL::FLOW_OP_SWITCH) { + code += _mktab(p_level) + "switch (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n"; + code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cfnode->flow_op == SL::FLOW_OP_CASE) { + code += _mktab(p_level) + "case " + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ":\n"; + code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cfnode->flow_op == SL::FLOW_OP_DEFAULT) { + code += _mktab(p_level) + "default:\n"; + code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + } else if (cfnode->flow_op == SL::FLOW_OP_DO) { + code += _mktab(p_level) + "do"; + code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); + code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ");"; + } else if (cfnode->flow_op == SL::FLOW_OP_WHILE) { code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning) + ")\n"; @@ -734,7 +874,7 @@ Error ShaderCompilerGLES3::compile(VS::ShaderMode p_mode, const String &p_code, Vector<String> shader = p_code.split("\n"); for (int i = 0; i < shader.size(); i++) { - print_line(itos(i) + " " + shader[i]); + print_line(itos(i + 1) + " " + shader[i]); } _err_print_error(NULL, p_path.utf8().get_data(), parser.get_error_line(), parser.get_error_text().utf8().get_data(), ERR_HANDLER_SHADER); @@ -772,7 +912,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { /** CANVAS ITEM SHADER **/ actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy"; - actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp"; + actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv"; actions[VS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "gl_PointSize"; actions[VS::SHADER_CANVAS_ITEM].renames["WORLD_MATRIX"] = "modelview_matrix"; @@ -801,6 +941,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv"; actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light"; actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color"; + actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_VEC"] = "shadow_vec"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["COLOR"] = "#define COLOR_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["SCREEN_TEXTURE"] = "#define SCREEN_TEXTURE_USED\n"; @@ -809,6 +950,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMAL"] = "#define NORMAL_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["NORMALMAP"] = "#define NORMALMAP_USED\n"; actions[VS::SHADER_CANVAS_ITEM].usage_defines["LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n"; + actions[VS::SHADER_CANVAS_ITEM].usage_defines["SHADOW_VEC"] = "#define SHADOW_VEC_USED\n"; actions[VS::SHADER_CANVAS_ITEM].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n"; /** SPATIAL SHADER **/ @@ -824,6 +966,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["NORMAL"] = "normal"; actions[VS::SHADER_SPATIAL].renames["TANGENT"] = "tangent"; actions[VS::SHADER_SPATIAL].renames["BINORMAL"] = "binormal"; + actions[VS::SHADER_SPATIAL].renames["POSITION"] = "position"; actions[VS::SHADER_SPATIAL].renames["UV"] = "uv_interp"; actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp"; actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp"; @@ -860,6 +1003,7 @@ 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"; @@ -888,6 +1032,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].usage_defines["COLOR"] = "#define ENABLE_COLOR_INTERP\n"; actions[VS::SHADER_SPATIAL].usage_defines["INSTANCE_CUSTOM"] = "#define ENABLE_INSTANCE_CUSTOM\n"; actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\n"; + actions[VS::SHADER_SPATIAL].usage_defines["POSITION"] = "#define OVERRIDE_POSITION\n"; actions[VS::SHADER_SPATIAL].usage_defines["SSS_STRENGTH"] = "#define ENABLE_SSS\n"; actions[VS::SHADER_SPATIAL].usage_defines["TRANSMISSION"] = "#define TRANSMISSION_USED\n"; @@ -927,13 +1072,14 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { 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"; + actions[VS::SHADER_SPATIAL].render_mode_defines["shadow_to_opacity"] = "#define USE_SHADOW_TO_OPACITY\n"; /* PARTICLES SHADER */ actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color"; actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz"; actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass"; - actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "active"; + actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active"; actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart"; actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom"; actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform"; @@ -946,9 +1092,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_PARTICLES].renames["EMISSION_TRANSFORM"] = "emission_transform"; actions[VS::SHADER_PARTICLES].renames["RANDOM_SEED"] = "random_seed"; - actions[VS::SHADER_SPATIAL].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; + actions[VS::SHADER_PARTICLES].render_mode_defines["disable_force"] = "#define DISABLE_FORCE\n"; + actions[VS::SHADER_PARTICLES].render_mode_defines["disable_velocity"] = "#define DISABLE_VELOCITY\n"; + actions[VS::SHADER_PARTICLES].render_mode_defines["keep_data"] = "#define ENABLE_KEEP_DATA\n"; vertex_name = "vertex"; fragment_name = "fragment"; diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h index 1f903b8935..79f5c50f88 100644 --- a/drivers/gles3/shader_compiler_gles3.h +++ b/drivers/gles3/shader_compiler_gles3.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 799179e8d4..ac911993be 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -133,15 +133,6 @@ bool ShaderGLES3::bind() { active = this; uniforms_dirty = true; - /* - * why on earth is this code here? - for (int i=0;i<texunit_pair_count;i++) { - - glUniform1i(texunit_pairs[i].location, texunit_pairs[i].index); - DEBUG_TEST_ERROR("Uniform 1 i"); - } - -*/ return true; } @@ -219,20 +210,15 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { strings.push_back("#version 300 es\n"); #endif - int define_line_ofs = 1; - for (int i = 0; i < custom_defines.size(); i++) { strings.push_back(custom_defines[i].get_data()); - define_line_ofs++; } for (int j = 0; j < conditional_count; j++) { bool enable = ((1 << j) & conditional_version.version); strings.push_back(enable ? conditional_defines[j] : ""); - if (enable) - define_line_ofs++; if (enable) { DEBUG_PRINT(conditional_defines[j]); @@ -253,7 +239,6 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { ERR_FAIL_COND_V(!custom_code_map.has(conditional_version.code_version), NULL); cc = &custom_code_map[conditional_version.code_version]; v.code_version = cc->version; - define_line_ofs += 2; } /* CREATE PROGRAM */ @@ -493,7 +478,7 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { glDeleteShader(v.vert_id); glDeleteProgram(v.id); v.id = 0; - ERR_FAIL_COND_V(iloglen <= 0, NULL); + ERR_FAIL_COND_V(iloglen < 0, NULL); } if (iloglen == 0) { @@ -565,6 +550,9 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { glUseProgram(0); v.ok = true; + if (cc) { + cc->versions.insert(conditional_version.version); + } return &v; } @@ -747,8 +735,26 @@ void ShaderGLES3::set_custom_shader(uint32_t p_code_id) { void ShaderGLES3::free_custom_shader(uint32_t p_code_id) { ERR_FAIL_COND(!custom_code_map.has(p_code_id)); - if (conditional_version.code_version == p_code_id) - conditional_version.code_version = 0; //bye + if (conditional_version.code_version == p_code_id) { + conditional_version.code_version = 0; //do not keep using a version that is going away + unbind(); + } + + VersionKey key; + key.code_version = p_code_id; + for (Set<uint32_t>::Element *E = custom_code_map[p_code_id].versions.front(); E; E = E->next()) { + key.version = E->get(); + ERR_CONTINUE(!version_map.has(key)); + Version &v = version_map[key]; + + glDeleteShader(v.vert_id); + glDeleteShader(v.frag_id); + glDeleteProgram(v.id); + memdelete_arr(v.uniform_location); + v.id = 0; + + version_map.erase(key); + } custom_code_map.erase(p_code_id); } diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h index 9db4942163..d8d49868f4 100644 --- a/drivers/gles3/shader_gles3.h +++ b/drivers/gles3/shader_gles3.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -45,10 +45,6 @@ #include <stdio.h> -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class ShaderGLES3 { protected: struct Enum { @@ -117,6 +113,7 @@ private: uint32_t version; Vector<StringName> texture_uniforms; Vector<CharString> custom_defines; + Set<uint32_t> versions; }; struct Version { @@ -128,11 +125,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; @@ -286,7 +285,9 @@ private: glUniformMatrix4fv(p_uniform, 1, false, matrix); } break; - default: { ERR_FAIL(); } // do nothing + default: { + ERR_FAIL(); + } // do nothing } } 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 5203f53fa2..e83f53d648 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -92,11 +92,6 @@ const bool at_light_pass = true; const bool at_light_pass = false; #endif -#ifdef USE_PARTICLES -uniform int h_frames; -uniform int v_frames; -#endif - #if defined(USE_MATERIAL) /* clang-format off */ @@ -122,7 +117,12 @@ void main() { #ifdef USE_INSTANCING 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; + +#ifdef USE_INSTANCE_CUSTOM vec4 instance_custom = instance_custom_data; +#else + vec4 instance_custom = vec4(0.0); +#endif #else mat4 extra_matrix_instance = extra_matrix; @@ -146,19 +146,12 @@ void main() { #ifdef USE_PARTICLES //scale by texture size outvec.xy /= color_texpixel_size; - - //compute h and v frames and adjust UV interp for animation - int total_frames = h_frames * v_frames; - int frame = min(int(float(total_frames) * instance_custom.z), total_frames - 1); - float frame_w = 1.0 / float(h_frames); - float frame_h = 1.0 / float(v_frames); - uv_interp.x = uv_interp.x * frame_w + frame_w * float(frame % h_frames); - uv_interp.y = uv_interp.y * frame_h + frame_h * float(frame / h_frames); - #endif #define extra_matrix extra_matrix_instance + //for compatibility with the fragment shader we need to use uv here + vec2 uv = uv_interp; { /* clang-format off */ @@ -167,6 +160,8 @@ VERTEX_SHADER_CODE /* clang-format on */ } + uv_interp = uv; + #ifdef USE_NINEPATCH pixel_size_interp = abs(dst_rect.zw) * vertex; @@ -182,8 +177,10 @@ VERTEX_SHADER_CODE color_interp = color; #ifdef USE_PIXEL_SNAP - outvec.xy = floor(outvec + 0.5).xy; + // precision issue on some hardware creates artifacts within texture + // offset uv by a small amount to avoid + uv_interp += 1e-5; #endif #ifdef USE_SKELETON @@ -348,6 +345,7 @@ void light_compute( inout vec4 light_color, vec2 light_uv, inout vec4 shadow_color, + inout vec2 shadow_vec, vec3 normal, vec2 uv, #if defined(SCREEN_UV_USED) @@ -492,6 +490,7 @@ void main() { #if defined(NORMALMAP_USED) vec3 normal_map = vec3(0.0, 0.0, 1.0); + normal_used = true; #endif /* clang-format off */ @@ -505,7 +504,7 @@ FRAGMENT_SHADER_CODE #endif } #ifdef DEBUG_ENCODED_32 - highp float enc32 = dot(color, highp vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1)); + highp float enc32 = dot(color, highp vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1.0)); color = vec4(vec3(enc32), 1.0); #endif @@ -514,6 +513,7 @@ FRAGMENT_SHADER_CODE #ifdef USE_LIGHTING vec2 light_vec = transformed_light_uv; + vec2 shadow_vec = transformed_light_uv; if (normal_used) { normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy; @@ -541,6 +541,7 @@ FRAGMENT_SHADER_CODE real_light_color, light_uv, real_light_shadow_color, + shadow_vec, normal, uv, #if defined(SCREEN_UV_USED) @@ -559,8 +560,16 @@ FRAGMENT_SHADER_CODE color *= light; #ifdef USE_SHADOWS - light_vec = light_uv_interp.zw; //for shadows - float angle_to_light = -atan(light_vec.x, light_vec.y); +#ifdef SHADOW_VEC_USED + mat3 inverse_light_matrix = mat3(light_matrix); + inverse_light_matrix[0] = normalize(inverse_light_matrix[0]); + inverse_light_matrix[1] = normalize(inverse_light_matrix[1]); + inverse_light_matrix[2] = normalize(inverse_light_matrix[2]); + shadow_vec = (mat3(inverse_light_matrix) * vec3(shadow_vec, 0.0)).xy; +#else + shadow_vec = light_uv_interp.zw; +#endif + float angle_to_light = -atan(shadow_vec.x, shadow_vec.y); float PI = 3.14159265358979323846264; /*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays float ang*/ @@ -571,18 +580,18 @@ FRAGMENT_SHADER_CODE vec2 point; float sh; if (abs_angle < 45.0 * PI / 180.0) { - point = light_vec; + point = shadow_vec; sh = 0.0 + (1.0 / 8.0); } else if (abs_angle > 135.0 * PI / 180.0) { - point = -light_vec; + point = -shadow_vec; sh = 0.5 + (1.0 / 8.0); } else if (angle_to_light > 0.0) { - point = vec2(light_vec.y, -light_vec.x); + point = vec2(shadow_vec.y, -shadow_vec.x); sh = 0.25 + (1.0 / 8.0); } else { - point = vec2(-light_vec.y, light_vec.x); + point = vec2(-shadow_vec.y, shadow_vec.x); sh = 0.75 + (1.0 / 8.0); } @@ -596,7 +605,7 @@ FRAGMENT_SHADER_CODE #ifdef USE_RGBA_SHADOWS -#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1)) +#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (255.0 * 255.0 * 255.0), 1.0 / (255.0 * 255.0), 1.0 / 255.0, 1.0)) #else diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl index 68d0713385..4f706c5505 100644 --- a/drivers/gles3/shaders/canvas_shadow.glsl +++ b/drivers/gles3/shaders/canvas_shadow.glsl @@ -35,8 +35,8 @@ void main() { #ifdef USE_RGBA_SHADOWS - highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0)); - comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0); + highp vec4 comp = fract(depth * vec4(255.0 * 255.0 * 255.0, 255.0 * 255.0, 255.0, 1.0)); + comp -= comp.xxyz * vec4(0.0, 1.0 / 255.0, 1.0 / 255.0, 1.0 / 255.0); distance_buf = comp; #else diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index a5637537d2..1952e201aa 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -18,10 +18,19 @@ out vec2 uv_interp; out vec2 uv2_interp; +// These definitions are here because the shader-wrapper builder does +// not understand `#elif defined()` +#ifdef USE_DISPLAY_TRANSFORM +#endif + #ifdef USE_COPY_SECTION uniform vec4 copy_section; +#elif defined(USE_DISPLAY_TRANSFORM) + +uniform highp mat4 display_transform; + #endif void main() { @@ -44,6 +53,9 @@ void main() { uv_interp = copy_section.xy + uv_interp * copy_section.zw; gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0; +#elif defined(USE_DISPLAY_TRANSFORM) + + uv_interp = (display_transform * vec4(uv_in, 1.0, 1.0)).xy; #endif } @@ -61,24 +73,47 @@ in vec3 cube_interp; #else in vec2 uv_interp; #endif -/* clang-format on */ #ifdef USE_ASYM_PANO uniform highp mat4 pano_transform; uniform highp vec4 asym_proj; #endif +// These definitions are here because the shader-wrapper builder does +// not understand `#elif defined()` +#ifdef USE_TEXTURE3D +#endif +#ifdef USE_TEXTURE2DARRAY +#endif +#ifdef YCBCR_TO_SRGB +#endif + #ifdef USE_CUBEMAP uniform samplerCube source_cube; //texunit:0 +#elif defined(USE_TEXTURE3D) +uniform sampler3D source_3d; //texunit:0 +#elif defined(USE_TEXTURE2DARRAY) +uniform sampler2DArray source_2d_array; //texunit:0 #else uniform sampler2D source; //texunit:0 #endif +#ifdef SEP_CBCR_TEXTURE +uniform sampler2D CbCr; //texunit:1 +#endif + +/* clang-format on */ + +#if defined(USE_TEXTURE3D) || defined(USE_TEXTURE2DARRAY) +uniform float layer; +#endif + #ifdef USE_MULTIPLIER uniform float multiplier; #endif #if defined(USE_PANORAMA) || defined(USE_ASYM_PANO) +uniform highp mat4 sky_transform; vec4 texturePanorama(vec3 normal, sampler2D pano) { @@ -96,7 +131,6 @@ vec4 texturePanorama(vec3 normal, sampler2D pano) { #endif -uniform float stuff; uniform vec2 pixel_size; in vec2 uv2_interp; @@ -121,19 +155,24 @@ void main() { #ifdef USE_PANORAMA - vec4 color = texturePanorama(normalize(cube_interp), source); + vec3 cube_normal = normalize(cube_interp); + cube_normal.z = -cube_normal.z; + cube_normal = mat3(sky_transform) * cube_normal; + cube_normal.z = -cube_normal.z; + + vec4 color = texturePanorama(cube_normal, source); #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. + // Asymmetrical projection means the center of projection is no longer in the center of the screen but shifted. // 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.z = -1.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 = mat3(sky_transform) * mat3(pano_transform) * cube_normal; cube_normal.z = -cube_normal.z; vec4 color = texturePanorama(normalize(cube_normal.xyz), source); @@ -141,14 +180,34 @@ void main() { #elif defined(USE_CUBEMAP) vec4 color = texture(source_cube, normalize(cube_interp)); +#elif defined(USE_TEXTURE3D) + vec4 color = textureLod(source_3d, vec3(uv_interp, layer), 0.0); +#elif defined(USE_TEXTURE2DARRAY) + vec4 color = textureLod(source_2d_array, vec3(uv_interp, layer), 0.0); +#elif defined(SEP_CBCR_TEXTURE) + vec4 color; + color.r = textureLod(source, uv_interp, 0.0).r; + color.gb = textureLod(CbCr, uv_interp, 0.0).rg - vec2(0.5, 0.5); + color.a = 1.0; #else vec4 color = textureLod(source, uv_interp, 0.0); #endif #ifdef LINEAR_TO_SRGB - //regular Linear -> SRGB conversion + // regular Linear -> SRGB conversion vec3 a = vec3(0.055); color.rgb = mix((vec3(1.0) + a) * pow(color.rgb, vec3(1.0 / 2.4)) - a, 12.92 * color.rgb, lessThan(color.rgb, vec3(0.0031308))); + +#elif defined(YCBCR_TO_SRGB) + + // YCbCr -> SRGB conversion + // Using BT.709 which is the standard for HDTV + color.rgb = mat3( + vec3(1.00000, 1.00000, 1.00000), + vec3(0.00000, -0.18732, 1.85560), + vec3(1.57481, -0.46813, 0.00000)) * + color.rgb; + #endif #ifdef SRGB_TO_LINEAR diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl index f65f798ff0..619e29b130 100644 --- a/drivers/gles3/shaders/cubemap_filter.glsl +++ b/drivers/gles3/shaders/cubemap_filter.glsl @@ -163,7 +163,7 @@ vec2 Hammersley(uint i, uint N) { #else -#define SAMPLE_COUNT 512u +#define SAMPLE_COUNT 1024u #endif diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index b67d06bc10..ff5a9f326f 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -94,6 +94,7 @@ uniform sampler2D source_dof_original; //texunit:2 uniform float exposure; uniform float white; +uniform highp float luminance_cap; #ifdef GLOW_USE_AUTO_EXPOSURE @@ -116,12 +117,13 @@ void main() { #ifdef GAUSSIAN_HORIZONTAL vec2 pix_size = pixel_size; pix_size *= 0.5; //reading from larger buffer, so use more samples + // sigma 2 vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.214607; color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.157305; + color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.131514; color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.071303; color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.189879; - color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.157305; + color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.131514; color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.071303; frag_color = color; #endif @@ -271,7 +273,7 @@ void main() { float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom); - frag_color *= feedback; + frag_color = min(frag_color * feedback, vec4(luminance_cap)); #endif 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 7da20dfa00..403de25dd0 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -42,11 +42,9 @@ layout(location = 4) in vec2 uv_attrib; layout(location = 5) in vec2 uv2_attrib; #endif -uniform float normal_mult; - #ifdef USE_SKELETON layout(location = 6) in uvec4 bone_indices; // attrib:6 -layout(location = 7) in vec4 bone_weights; // attrib:7 +layout(location = 7) in highp vec4 bone_weights; // attrib:7 #endif #ifdef USE_INSTANCING @@ -98,6 +96,8 @@ layout(std140) uniform SceneData { // ubo:0 bool fog_depth_enabled; highp float fog_depth_begin; + highp float fog_depth_end; + mediump float fog_density; highp float fog_depth_curve; bool fog_transmit_enabled; highp float fog_transmit_curve; @@ -167,15 +167,61 @@ out vec4 specular_light_interp; void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float roughness, inout vec3 diffuse, inout vec3 specular) { - float dotNL = max(dot(N, L), 0.0); - diffuse += dotNL * light_color / M_PI; + 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 + + diffuse += light_color * diffuse_brdf_NL; 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 dotNH = max(dot(N, H), 0.0); - float intensity = (roughness >= 1.0 ? 1.0 : pow(dotNH, (1.0 - roughness) * 256.0)); - specular += light_color * intensity; + 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) * (1.0 / (8.0 * M_PI)); + specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); +#endif + + specular += specular_brdf_NL * light_color * (1.0 / M_PI); } } @@ -268,7 +314,7 @@ void main() { highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0); - mat4 world_matrix = world_transform; + highp mat4 world_matrix = world_transform; #ifdef USE_INSTANCING @@ -278,11 +324,10 @@ void main() { } #endif - vec3 normal = normal_attrib * normal_mult; + vec3 normal = normal_attrib; #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) vec3 tangent = tangent_attrib.xyz; - tangent *= normal_mult; float binormalf = tangent_attrib.a; #endif @@ -307,6 +352,10 @@ void main() { uv2_interp = uv2_attrib; #endif +#ifdef OVERRIDE_POSITION + highp vec4 position; +#endif + #if defined(USE_INSTANCING) && defined(ENABLE_INSTANCE_CUSTOM) vec4 instance_custom = instance_custom_data; #else @@ -346,44 +395,46 @@ void main() { ivec4 bone_indicesi = ivec4(bone_indices); // cast to signed int ivec2 tex_ofs = ivec2(bone_indicesi.x % 256, (bone_indicesi.x / 256) * 3); - highp mat3x4 m; - m = mat3x4( + highp mat4 m; + m = mat4( texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) * + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), + vec4(0.0, 0.0, 0.0, 1.0)) * bone_weights.x; tex_ofs = ivec2(bone_indicesi.y % 256, (bone_indicesi.y / 256) * 3); - m += mat3x4( + m += mat4( texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) * + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), + vec4(0.0, 0.0, 0.0, 1.0)) * bone_weights.y; tex_ofs = ivec2(bone_indicesi.z % 256, (bone_indicesi.z / 256) * 3); - m += mat3x4( + m += mat4( texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) * + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), + vec4(0.0, 0.0, 0.0, 1.0)) * bone_weights.z; tex_ofs = ivec2(bone_indicesi.w % 256, (bone_indicesi.w / 256) * 3); - m += mat3x4( + m += mat4( texelFetch(skeleton_texture, tex_ofs, 0), texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0), - texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) * + texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0), + vec4(0.0, 0.0, 0.0, 1.0)) * bone_weights.w; - mat4 bone_matrix = transpose(mat4(m[0], m[1], m[2], vec4(0.0, 0.0, 0.0, 1.0))); - - world_matrix = bone_matrix * world_matrix; + world_matrix = world_matrix * transpose(m); } #endif - mat4 modelview = camera_inverse_matrix * world_matrix; + highp mat4 modelview = camera_inverse_matrix * world_matrix; { /* clang-format off */ @@ -462,7 +513,11 @@ VERTEX_SHADER_CODE #endif //RENDER_DEPTH +#ifdef OVERRIDE_POSITION + gl_Position = position; +#else gl_Position = projection_matrix * vec4(vertex_interp, 1.0); +#endif position_interp = gl_Position; @@ -675,6 +730,8 @@ layout(std140) uniform SceneData { bool fog_depth_enabled; highp float fog_depth_begin; + highp float fog_depth_end; + mediump float fog_density; highp float fog_depth_curve; bool fog_transmit_enabled; highp float fog_transmit_curve; @@ -920,13 +977,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, inout float alpha) { #if defined(USE_LIGHT_SHADER_CODE) // light is written by the light shader @@ -948,6 +1006,18 @@ LIGHT_SHADER_CODE float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + vec3 H = normalize(V + L); +#endif + +#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cNdotH = max(dot(N, H), 0.0); +#endif + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cLdotH = max(dot(L, H), 0.0); +#endif + if (metallic < 1.0) { #if defined(DIFFUSE_OREN_NAYAR) vec3 diffuse_brdf_NL; @@ -982,13 +1052,9 @@ LIGHT_SHADER_CODE #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); + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; /* float energyBias = mix(roughness, 0.0, 0.5); @@ -1025,13 +1091,9 @@ LIGHT_SHADER_CODE #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); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); specular_light += light_color * intensity * specular_blob_intensity * attenuation; @@ -1042,7 +1104,7 @@ LIGHT_SHADER_CODE 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); + phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); specular_light += light_color * intensity * specular_blob_intensity * attenuation; @@ -1062,59 +1124,51 @@ LIGHT_SHADER_CODE #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_ggx = 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_ggx / aspect; + float ay = alpha_ggx * aspect; float XdotH = dot(T, H); float YdotH = dot(B, H); float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); #else - float alpha = roughness * roughness; - float D = D_GGX(cNdotH, alpha); - float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); + float alpha_ggx = roughness * roughness; + float D = D_GGX(cNdotH, alpha_ggx); + float G = G_GGX_2cos(cNdotL, alpha_ggx) * G_GGX_2cos(cNdotV, alpha_ggx); #endif // F - //float F0 = 1.0; - //float cLdotH5 = SchlickFresnel(cLdotH); - //float F = mix(cLdotH5, 1.0, F0); + vec3 f0 = F0(metallic, specular, diffuse_color); + float cLdotH5 = SchlickFresnel(cLdotH); + 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 #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); + 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 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 specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; - } + specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #endif } +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(1.0 - length(attenuation), 0.0, 1.0)); +#endif + #endif //defined(USE_LIGHT_SHADER_CODE) } @@ -1136,8 +1190,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)); @@ -1146,7 +1201,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)); @@ -1188,7 +1245,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, inout float alpha) { vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex; float light_length = length(light_rel_vec); @@ -1242,10 +1299,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, alpha); } -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, inout float alpha) { vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex; float light_length = length(light_rel_vec); @@ -1277,7 +1334,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, alpha); } 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) { @@ -1337,7 +1394,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; @@ -1468,8 +1525,8 @@ void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds, ve #define MAX_CONE_DIRS 6 vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( - vec3(0, 0, 1), - vec3(0.866025, 0, 0.5), + vec3(0.0, 0.0, 1.0), + vec3(0.866025, 0.0, 0.5), vec3(0.267617, 0.823639, 0.5), vec3(-0.700629, 0.509037, 0.5), vec3(-0.700629, -0.509037, 0.5), @@ -1483,10 +1540,10 @@ void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds, ve #define MAX_CONE_DIRS 4 vec3 cone_dirs[MAX_CONE_DIRS] = vec3[]( - vec3(0.707107, 0, 0.707107), - vec3(0, 0.707107, 0.707107), - vec3(-0.707107, 0, 0.707107), - vec3(0, -0.707107, 0.707107)); + vec3(0.707107, 0.0, 0.707107), + vec3(0.0, 0.707107, 0.707107), + vec3(-0.707107, 0.0, 0.707107), + vec3(0.0, -0.707107, 0.707107)); float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25); float cone_angle_tan = 0.98269; @@ -1507,7 +1564,7 @@ void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds, ve //irradiance - vec3 irr_light = voxel_cone_trace(probe, cell_size, probe_pos, environment, blend_ambient, ref_vec, max(min_ref_tan, tan(roughness * 0.5 * M_PI)), max_distance, p_bias); + vec3 irr_light = voxel_cone_trace(probe, cell_size, probe_pos, environment, blend_ambient, ref_vec, max(min_ref_tan, tan(roughness * 0.5 * M_PI * 0.99)), max_distance, p_bias); irr_light *= multiplier; //irr_light=vec3(0.0); @@ -1522,7 +1579,7 @@ void gi_probes_compute(vec3 pos, vec3 normal, float roughness, inout vec3 out_sp vec3 ref_vec = normalize(reflect(normalize(pos), normal)); //find arbitrary tangent and bitangent, then build a matrix - vec3 v0 = abs(normal.z) < 0.999 ? vec3(0, 0, 1) : vec3(0, 1, 0); + vec3 v0 = abs(normal.z) < 0.999 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 1.0, 0.0); vec3 tangent = normalize(cross(v0, normal)); vec3 bitangent = normalize(cross(tangent, normal)); mat3 normal_mat = mat3(tangent, bitangent, normal); @@ -1568,6 +1625,7 @@ void main() { //lay out everything, whathever is unused is optimized away anyway highp vec3 vertex = vertex_interp; + vec3 view = -normalize(vertex_interp); vec3 albedo = vec3(1.0); vec3 transmission = vec3(0.0); float metallic = 0.0; @@ -1588,24 +1646,24 @@ void main() { float alpha = 1.0; -#if defined(DO_SIDE_CHECK) - float side = gl_FrontFacing ? 1.0 : -1.0; -#else - float side = 1.0; -#endif - #if defined(ALPHA_SCISSOR_USED) float alpha_scissor = 0.5; #endif #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - vec3 binormal = normalize(binormal_interp) * side; - vec3 tangent = normalize(tangent_interp) * side; + vec3 binormal = normalize(binormal_interp); + vec3 tangent = normalize(tangent_interp); #else vec3 binormal = vec3(0.0); vec3 tangent = vec3(0.0); #endif - vec3 normal = normalize(normal_interp) * side; + vec3 normal = normalize(normal_interp); + +#if defined(DO_SIDE_CHECK) + if (!gl_FrontFacing) { + normal = -normal; + } +#endif #if defined(ENABLE_UV_INTERP) vec2 uv = uv_interp; @@ -1642,11 +1700,13 @@ FRAGMENT_SHADER_CODE /* clang-format on */ } +#if !defined(USE_SHADOW_TO_OPACITY) + #if defined(ALPHA_SCISSOR_USED) if (alpha < alpha_scissor) { discard; } -#endif +#endif // ALPHA_SCISSOR_USED #ifdef USE_OPAQUE_PREPASS @@ -1654,14 +1714,16 @@ FRAGMENT_SHADER_CODE discard; } -#endif +#endif // USE_OPAQUE_PREPASS + +#endif // !USE_SHADOW_TO_OPACITY #if defined(ENABLE_NORMALMAP) normalmap.xy = normalmap.xy * 2.0 - 1.0; normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. - normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; + normal = normalize(mix(normal, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)); #endif @@ -1702,7 +1764,7 @@ FRAGMENT_SHADER_CODE vec3 ambient_light; vec3 env_reflection_light = vec3(0.0, 0.0, 0.0); - vec3 eye_vec = -normalize(vertex_interp); + vec3 eye_vec = view; #ifdef USE_RADIANCE_MAP @@ -1739,6 +1801,7 @@ FRAGMENT_SHADER_CODE ambient_light = vec3(0.0, 0.0, 0.0); #else ambient_light = ambient_light_color.rgb; + env_reflection_light = bg_color.rgb * bg_energy; #endif //AMBIENT_LIGHT_DISABLED #endif @@ -1746,10 +1809,98 @@ FRAGMENT_SHADER_CODE ambient_light *= ambient_energy; float specular_blob_intensity = 1.0; + #if defined(SPECULAR_TOON) specular_blob_intensity *= specular * 2.0; #endif +#ifdef USE_GI_PROBES + gi_probes_compute(vertex, normal, roughness, env_reflection_light, ambient_light); + +#endif + +#ifdef USE_LIGHTMAP + ambient_light = texture(lightmap, uv2).rgb * lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE + { + vec3 cone_dirs[12] = vec3[]( + vec3(0.0, 0.0, 1.0), + vec3(0.866025, 0.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, 0.0, -1.0), + vec3(0.866025, 0.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 + +#ifdef USE_FORWARD_LIGHTING + + highp vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); + highp vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); + for (int i = 0; i < reflection_count; i++) { + reflection_process(reflection_indices[i], vertex, normal, binormal, tangent, roughness, anisotropy, ambient_light, env_reflection_light, reflection_accum, ambient_accum); + } + + if (reflection_accum.a > 0.0) { + specular_light += reflection_accum.rgb / reflection_accum.a; + } else { + specular_light += env_reflection_light; + } +#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE) + if (ambient_accum.a > 0.0) { + ambient_light = ambient_accum.rgb / ambient_accum.a; + } +#endif +#endif + + { + +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + + // scales the specular reflections, needs to be be computed before lighting happens, + // but after environment, GI, and reflection probes are added + // Environment brdf approximation (Lazarov 2013) + // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile + 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_vec), 0.0, 1.0); + float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; + + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; +#endif + } + #if defined(USE_LIGHT_DIRECTIONAL) vec3 light_attenuation = vec3(1.0); @@ -1892,91 +2043,49 @@ 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, alpha); #endif #endif //#USE_LIGHT_DIRECTIONAL -#ifdef USE_GI_PROBES - gi_probes_compute(vertex, normal, roughness, env_reflection_light, ambient_light); - -#endif - -#ifdef USE_LIGHTMAP - ambient_light = texture(lightmap, uv2).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 - #ifdef USE_FORWARD_LIGHTING - highp vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0); - highp vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0); - for (int i = 0; i < reflection_count; i++) { - reflection_process(reflection_indices[i], vertex, normal, binormal, tangent, roughness, anisotropy, ambient_light, env_reflection_light, reflection_accum, ambient_accum); - } - - if (reflection_accum.a > 0.0) { - specular_light += reflection_accum.rgb / reflection_accum.a; - } else { - specular_light += env_reflection_light; - } -#ifndef USE_LIGHTMAP - if (ambient_accum.a > 0.0) { - ambient_light = ambient_accum.rgb / ambient_accum.a; - } -#endif - #ifdef USE_VERTEX_LIGHTING diffuse_light *= albedo; #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, alpha); } 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, alpha); } #endif //USE_VERTEX_LIGHTING #endif +#ifdef USE_SHADOW_TO_OPACITY + alpha = min(alpha, clamp(length(ambient_light), 0.0, 1.0)); + +#if defined(ALPHA_SCISSOR_USED) + if (alpha < alpha_scissor) { + discard; + } +#endif // ALPHA_SCISSOR_USED + +#ifdef USE_OPAQUE_PREPASS + + if (alpha < opaque_prepass_threshold) { + discard; + } + +#endif // USE_OPAQUE_PREPASS + +#endif // USE_SHADOW_TO_OPACITY + #ifdef RENDER_DEPTH //nothing happens, so a tree-ssa optimizer will result in no fragment shader :) #else @@ -1991,30 +2100,10 @@ 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; - { - -#if defined(DIFFUSE_TOON) - //simplify for toon, as - specular_light *= specular * metallic * albedo * 2.0; -#else - // Environment brdf approximation (Lazarov 2013) - // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile - 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_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; - - vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo); - specular_light *= AB.x * specular_color + AB.y; -#endif - } - if (fog_color_enabled.a > 0.5) { float fog_amount = 0.0; @@ -2030,10 +2119,11 @@ FRAGMENT_SHADER_CODE //apply fog if (fog_depth_enabled) { + float fog_far = fog_depth_end > 0.0 ? fog_depth_end : z_far; - float fog_z = smoothstep(fog_depth_begin, z_far, length(vertex)); + float fog_z = smoothstep(fog_depth_begin, fog_far, length(vertex)); - fog_amount = pow(fog_z, fog_depth_curve); + fog_amount = pow(fog_z, fog_depth_curve) * fog_density; if (fog_transmit_enabled) { vec3 total_light = emission + ambient_light + specular_light + diffuse_light; float transmit = pow(fog_z, fog_transmit_curve); @@ -2050,7 +2140,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/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl index 86546319a0..39f1ea6155 100644 --- a/drivers/gles3/shaders/screen_space_reflection.glsl +++ b/drivers/gles3/shaders/screen_space_reflection.glsl @@ -77,7 +77,7 @@ void main() { return; } //ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0); - //ray_dir = normalize(vec3(1, 1, -1)); + //ray_dir = normalize(vec3(1.0, 1.0, -1.0)); //////////////// diff --git a/drivers/gles3/shaders/ssao.glsl b/drivers/gles3/shaders/ssao.glsl index be44365169..d9cdc3fc1f 100644 --- a/drivers/gles3/shaders/ssao.glsl +++ b/drivers/gles3/shaders/ssao.glsl @@ -16,15 +16,15 @@ void main() { #define TWO_PI 6.283185307179586476925286766559 #ifdef SSAO_QUALITY_HIGH -#define NUM_SAMPLES (80) +#define NUM_SAMPLES (16) #endif #ifdef SSAO_QUALITY_LOW -#define NUM_SAMPLES (15) +#define NUM_SAMPLES (8) #endif #if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH) -#define NUM_SAMPLES (40) +#define NUM_SAMPLES (12) #endif // If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index dd6d78849b..f1fe1742eb 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 brightness 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] @@ -160,9 +164,10 @@ vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f))); } -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); +// inputs are LINEAR, If Linear tonemapping is selected no transform is performed else outputs are clamped [0, 1] color +vec3 apply_tonemapping(vec3 color, float white) { +#ifdef USE_REINHARD_TONEMAPPER + return tonemap_reinhard(color, white); #endif #ifdef USE_FILMIC_TONEMAPPER @@ -173,7 +178,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 selected -> linear + return color; // no other selected -> linear: no color transform applied } vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels @@ -216,10 +221,14 @@ vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blendi #endif #ifdef USE_GLOW_SCREEN + //need color clamping + color = clamp(color, vec3(0.0f), vec3(1.0f)); color = max((color + glow) - (color * glow), vec3(0.0)); #endif #ifdef USE_GLOW_SOFTLIGHT + //need color clamping + color = clamp(color, vec3(0.0f), vec3(1.0)); glow = glow * vec3(0.5f) + vec3(0.5f); color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r))); @@ -261,14 +270,16 @@ void main() { color *= exposure; - // Early Tonemap & SRGB Conversion + // Early Tonemap & SRGB Conversion; note that Linear tonemapping does not clamp to [0, 1]; some operations below expect a [0, 1] range and will clamp color = apply_tonemapping(color, white); #ifdef KEEP_3D_LINEAR // leave color as is (-> don't convert to SRGB) #else - color = linear_to_srgb(color); // regular linear -> SRGB conversion + //need color clamping + color = clamp(color, vec3(0.0f), vec3(1.0f)); + color = linear_to_srgb(color); // regular linear -> SRGB conversion (needs clamped values) #endif // Glow @@ -278,6 +289,7 @@ void main() { // high dynamic range -> SRGB glow = apply_tonemapping(glow, white); + glow = clamp(glow, vec3(0.0f), vec3(1.0f)); glow = linear_to_srgb(glow); color = apply_glow(color, glow); diff --git a/drivers/png/SCsub b/drivers/png/SCsub index 39480351a6..87b54cecaf 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -26,23 +26,32 @@ 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]) + env_png.Prepend(CPPPATH=[thirdparty_dir]) + # Needed for drivers includes and in platform/javascript + env.Prepend(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": - env_png.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=2"]) - env_neon = env_png.Clone() + use_neon = "neon_enabled" in env and env["neon_enabled"] and os.name != "nt" + if use_neon: + env_png.Append(CPPDEFINES=[("PNG_ARM_NEON_OPT", 2)]) + else: + env_png.Append(CPPDEFINES=[("PNG_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 = [] neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/arm_init.c")) 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")) + neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/palette_neon_intrinsics.c")) 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 04acb9387e..f257fafd93 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -32,182 +32,26 @@ #include "core/os/os.h" #include "core/print_string.h" +#include "drivers/png/png_driver_common.h" #include <string.h> -void ImageLoaderPNG::_read_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) { - - FileAccess *f = (FileAccess *)png_get_io_ptr(png_ptr); - f->get_buffer((uint8_t *)data, p_length); -} - -/* -png_structp png_ptr = png_create_read_struct_2 - (PNG_LIBPNG_VER_STRING, (png_voidp)user_error_ptr, - user_error_fn, user_warning_fn, (png_voidp) - user_mem_ptr, user_malloc_fn, user_free_fn); -*/ -static png_voidp _png_malloc_fn(png_structp png_ptr, png_size_t size) { - - return memalloc(size); -} - -static void _png_free_fn(png_structp png_ptr, png_voidp ptr) { - - memfree(ptr); -} - -static void _png_error_function(png_structp, png_const_charp text) { - - ERR_PRINT(text); -} - -static void _png_warn_function(png_structp, png_const_charp text) { - - WARN_PRINT(text); -} - -typedef void(PNGAPI *png_error_ptr) PNGARG((png_structp, png_const_charp)); - -Error ImageLoaderPNG::_load_image(void *rf_up, png_rw_ptr p_func, Ref<Image> p_image) { - - png_structp png; - png_infop info; - - //png = png_create_read_struct(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, NULL, NULL); - - png = png_create_read_struct_2(PNG_LIBPNG_VER_STRING, (png_voidp)NULL, _png_error_function, _png_warn_function, (png_voidp)NULL, - _png_malloc_fn, _png_free_fn); - - ERR_FAIL_COND_V(!png, ERR_OUT_OF_MEMORY); - - info = png_create_info_struct(png); - if (!info) { - png_destroy_read_struct(&png, NULL, NULL); - ERR_PRINT("Out of Memory"); - return ERR_OUT_OF_MEMORY; - } - - if (setjmp(png_jmpbuf(png))) { - - png_destroy_read_struct(&png, NULL, NULL); - ERR_PRINT("PNG Corrupted"); - return ERR_FILE_CORRUPT; - } - - png_set_read_fn(png, (void *)rf_up, p_func); - - png_uint_32 width, height; - int depth, color; - - png_read_info(png, info); - png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); - - //https://svn.gov.pt/projects/ccidadao/repository/middleware-offline/trunk/_src/eidmw/FreeImagePTEiD/Source/FreeImage/PluginPNG.cpp - //png_get_text(png,info,) - /* - printf("Image width:%i\n", width); - printf("Image Height:%i\n", height); - printf("Bit depth:%i\n", depth); - printf("Color type:%i\n", color); - */ - - bool update_info = false; - - if (depth < 8) { //only bit dept 8 per channel is handled - - png_set_packing(png); - update_info = true; - }; - - if (png_get_color_type(png, info) == PNG_COLOR_TYPE_PALETTE) { - png_set_palette_to_rgb(png); - update_info = true; - } - - if (depth > 8) { - png_set_strip_16(png); - update_info = true; - } - - if (png_get_valid(png, info, PNG_INFO_tRNS)) { - //png_set_expand_gray_1_2_4_to_8(png); - png_set_tRNS_to_alpha(png); - update_info = true; - } - - if (update_info) { - png_read_update_info(png, info); - png_get_IHDR(png, info, &width, &height, &depth, &color, NULL, NULL, NULL); - } - - int components = 0; - - Image::Format fmt; - switch (color) { - - case PNG_COLOR_TYPE_GRAY: { - - fmt = Image::FORMAT_L8; - components = 1; - } break; - case PNG_COLOR_TYPE_GRAY_ALPHA: { - - fmt = Image::FORMAT_LA8; - components = 2; - } break; - case PNG_COLOR_TYPE_RGB: { - - fmt = Image::FORMAT_RGB8; - components = 3; - } break; - case PNG_COLOR_TYPE_RGB_ALPHA: { - - fmt = Image::FORMAT_RGBA8; - components = 4; - } break; - default: { +Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { - ERR_PRINT("INVALID PNG TYPE"); - png_destroy_read_struct(&png, &info, NULL); - return ERR_UNAVAILABLE; - } break; + const size_t buffer_size = f->get_len(); + PoolVector<uint8_t> file_buffer; + Error err = file_buffer.resize(buffer_size); + if (err) { + f->close(); + return err; } - - //int rowsize = png_get_rowbytes(png, info); - int rowsize = components * width; - - PoolVector<uint8_t> dstbuff; - - dstbuff.resize(rowsize * height); - - PoolVector<uint8_t>::Write dstbuff_write = dstbuff.write(); - - uint8_t *data = dstbuff_write.ptr(); - - uint8_t **row_p = memnew_arr(uint8_t *, height); - - for (unsigned int i = 0; i < height; i++) { - row_p[i] = &data[components * width * i]; + { + PoolVector<uint8_t>::Write writer = file_buffer.write(); + f->get_buffer(writer.ptr(), buffer_size); + f->close(); } - - png_read_image(png, (png_bytep *)row_p); - - memdelete_arr(row_p); - - p_image->create(width, height, 0, fmt, dstbuff); - - png_destroy_read_struct(&png, &info, NULL); - - return OK; -} - -Error ImageLoaderPNG::load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale) { - - Error err = _load_image(f, _read_png_data, p_image); - f->close(); - - return err; + PoolVector<uint8_t>::Read reader = file_buffer.read(); + return PNGDriverCommon::png_to_image(reader.ptr(), buffer_size, p_image); } void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const { @@ -215,181 +59,53 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const p_extensions->push_back("png"); } -struct PNGReadStatus { - - uint32_t offset; - uint32_t size; - const unsigned char *image; -}; - -static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t p_length) { - - 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); - } - memcpy(data, &rstatus->image[rstatus->offset], to_read); - rstatus->offset += to_read; - - if (to_read < p_length) { - memset(&data[to_read], 0, p_length - to_read); - } -} - -static Ref<Image> _load_mem_png(const uint8_t *p_png, int p_size) { - - PNGReadStatus prs; - prs.image = p_png; - prs.offset = 0; - prs.size = p_size; +Ref<Image> ImageLoaderPNG::load_mem_png(const uint8_t *p_png, int p_size) { Ref<Image> img; img.instance(); - Error err = ImageLoaderPNG::_load_image(&prs, user_read_data, img); + + Error err = PNGDriverCommon::png_to_image(p_png, p_size, img); ERR_FAIL_COND_V(err, Ref<Image>()); return img; } -static Ref<Image> _lossless_unpack_png(const PoolVector<uint8_t> &p_data) { +Ref<Image> ImageLoaderPNG::lossless_unpack_png(const PoolVector<uint8_t> &p_data) { - int len = p_data.size(); + const int len = p_data.size(); ERR_FAIL_COND_V(len < 4, Ref<Image>()); PoolVector<uint8_t>::Read r = p_data.read(); ERR_FAIL_COND_V(r[0] != 'P' || r[1] != 'N' || r[2] != 'G' || r[3] != ' ', Ref<Image>()); - return _load_mem_png(&r[4], len - 4); -} - -static void _write_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) { - - PoolVector<uint8_t> &v = *(PoolVector<uint8_t> *)png_get_io_ptr(png_ptr); - int vs = v.size(); - - v.resize(vs + p_length); - PoolVector<uint8_t>::Write w = v.write(); - copymem(&w[vs], data, p_length); + return load_mem_png(&r[4], len - 4); } -static PoolVector<uint8_t> _lossless_pack_png(const Ref<Image> &p_image) { - - Ref<Image> img = p_image->duplicate(); - - if (img->is_compressed()) - img->decompress(); - - ERR_FAIL_COND_V(img->is_compressed(), PoolVector<uint8_t>()); - - png_structp png_ptr; - png_infop info_ptr; - png_bytep *row_pointers; +PoolVector<uint8_t> ImageLoaderPNG::lossless_pack_png(const Ref<Image> &p_image) { - /* initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + PoolVector<uint8_t> out_buffer; - ERR_FAIL_COND_V(!png_ptr, PoolVector<uint8_t>()); - - info_ptr = png_create_info_struct(png_ptr); - - ERR_FAIL_COND_V(!info_ptr, PoolVector<uint8_t>()); - - if (setjmp(png_jmpbuf(png_ptr))) { - ERR_FAIL_V(PoolVector<uint8_t>()); - } - PoolVector<uint8_t> ret; - ret.push_back('P'); - ret.push_back('N'); - ret.push_back('G'); - ret.push_back(' '); - - png_set_write_fn(png_ptr, &ret, _write_png_data, NULL); - - /* write header */ - if (setjmp(png_jmpbuf(png_ptr))) { - ERR_FAIL_V(PoolVector<uint8_t>()); - } - - int pngf = 0; - int cs = 0; - - switch (img->get_format()) { - - case Image::FORMAT_L8: { - - pngf = PNG_COLOR_TYPE_GRAY; - cs = 1; - } break; - case Image::FORMAT_LA8: { - - pngf = PNG_COLOR_TYPE_GRAY_ALPHA; - cs = 2; - } break; - case Image::FORMAT_RGB8: { - - pngf = PNG_COLOR_TYPE_RGB; - cs = 3; - } break; - case Image::FORMAT_RGBA8: { - - pngf = PNG_COLOR_TYPE_RGB_ALPHA; - cs = 4; - } break; - default: { - - if (img->detect_alpha()) { - - img->convert(Image::FORMAT_RGBA8); - pngf = PNG_COLOR_TYPE_RGB_ALPHA; - cs = 4; - } else { - - img->convert(Image::FORMAT_RGB8); - pngf = PNG_COLOR_TYPE_RGB; - cs = 3; - } - } - } - - int w = img->get_width(); - int h = img->get_height(); - png_set_IHDR(png_ptr, info_ptr, w, h, - 8, pngf, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_write_info(png_ptr, info_ptr); - - /* write bytes */ - if (setjmp(png_jmpbuf(png_ptr))) { + // add Godot's own "PNG " prefix + if (out_buffer.resize(4) != OK) { ERR_FAIL_V(PoolVector<uint8_t>()); } - PoolVector<uint8_t>::Read r = img->get_data().read(); - - row_pointers = (png_bytep *)memalloc(sizeof(png_bytep) * h); - for (int i = 0; i < h; i++) { - - row_pointers[i] = (png_bytep)&r[i * w * cs]; + // scope for writer lifetime + { + // must be closed before call to image_to_png + PoolVector<uint8_t>::Write writer = out_buffer.write(); + copymem(writer.ptr(), "PNG ", 4); } - png_write_image(png_ptr, row_pointers); - - memfree(row_pointers); - - /* end write */ - if (setjmp(png_jmpbuf(png_ptr))) { + Error err = PNGDriverCommon::image_to_png(p_image, out_buffer); + if (err) { ERR_FAIL_V(PoolVector<uint8_t>()); } - png_write_end(png_ptr, NULL); - - return ret; + return out_buffer; } ImageLoaderPNG::ImageLoaderPNG() { - Image::_png_mem_loader_func = _load_mem_png; - Image::lossless_unpacker = _lossless_unpack_png; - Image::lossless_packer = _lossless_pack_png; + Image::_png_mem_loader_func = load_mem_png; + Image::lossless_unpacker = lossless_unpack_png; + Image::lossless_packer = lossless_pack_png; } diff --git a/drivers/png/image_loader_png.h b/drivers/png/image_loader_png.h index 5dff7e3902..c910c31f1e 100644 --- a/drivers/png/image_loader_png.h +++ b/drivers/png/image_loader_png.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -33,17 +33,13 @@ #include "core/io/image_loader.h" -#include <png.h> - -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ class ImageLoaderPNG : public ImageFormatLoader { - - static void _read_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length); +private: + static PoolVector<uint8_t> lossless_pack_png(const Ref<Image> &p_image); + static Ref<Image> lossless_unpack_png(const PoolVector<uint8_t> &p_data); + static Ref<Image> load_mem_png(const uint8_t *p_png, int p_size); public: - static Error _load_image(void *rf_up, png_rw_ptr p_func, Ref<Image> p_image); virtual Error load_image(Ref<Image> p_image, FileAccess *f, bool p_force_linear, float p_scale); virtual void get_recognized_extensions(List<String> *p_extensions) const; ImageLoaderPNG(); diff --git a/drivers/png/png_driver_common.cpp b/drivers/png/png_driver_common.cpp new file mode 100644 index 0000000000..7deac1d118 --- /dev/null +++ b/drivers/png/png_driver_common.cpp @@ -0,0 +1,204 @@ +/*************************************************************************/ +/* png_driver_common.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 "png_driver_common.h" + +#include "core/os/os.h" + +#include <png.h> +#include <string.h> + +namespace PNGDriverCommon { + +// Print any warnings. +// On error, set explain and return true. +// Call should be wrapped in ERR_FAIL_COND +static bool check_error(const png_image &image) { + const png_uint_32 failed = PNG_IMAGE_FAILED(image); + if (failed & PNG_IMAGE_ERROR) { + ERR_EXPLAINC(image.message); + return true; + } else if (failed) { +#ifdef TOOLS_ENABLED + // suppress this warning, to avoid log spam when opening assetlib + const static char *const noisy = "iCCP: known incorrect sRGB profile"; + const Engine *const eng = Engine::get_singleton(); + if (eng && eng->is_editor_hint() && !strcmp(image.message, noisy)) { + return false; + } +#endif + WARN_PRINT(image.message); + } + return false; +} + +Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image) { + + png_image png_img; + zeromem(&png_img, sizeof(png_img)); + png_img.version = PNG_IMAGE_VERSION; + + // fetch image properties + int success = png_image_begin_read_from_memory(&png_img, p_source, p_size); + ERR_FAIL_COND_V(check_error(png_img), ERR_FILE_CORRUPT); + ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT); + + // flags to be masked out of input format to give target format + const png_uint_32 format_mask = ~( + // convert component order to RGBA + PNG_FORMAT_FLAG_BGR | PNG_FORMAT_FLAG_AFIRST + // convert 16 bit components to 8 bit + | PNG_FORMAT_FLAG_LINEAR + // convert indexed image to direct color + | PNG_FORMAT_FLAG_COLORMAP); + + png_img.format &= format_mask; + + Image::Format dest_format; + switch (png_img.format) { + case PNG_FORMAT_GRAY: + dest_format = Image::FORMAT_L8; + break; + case PNG_FORMAT_GA: + dest_format = Image::FORMAT_LA8; + break; + case PNG_FORMAT_RGB: + dest_format = Image::FORMAT_RGB8; + break; + case PNG_FORMAT_RGBA: + dest_format = Image::FORMAT_RGBA8; + break; + default: + png_image_free(&png_img); // only required when we return before finish_read + ERR_PRINT("Unsupported png format."); + return ERR_UNAVAILABLE; + } + + const png_uint_32 stride = PNG_IMAGE_ROW_STRIDE(png_img); + PoolVector<uint8_t> buffer; + Error err = buffer.resize(PNG_IMAGE_BUFFER_SIZE(png_img, stride)); + if (err) { + png_image_free(&png_img); // only required when we return before finish_read + return err; + } + PoolVector<uint8_t>::Write writer = buffer.write(); + + // read image data to buffer and release libpng resources + success = png_image_finish_read(&png_img, NULL, writer.ptr(), stride, NULL); + ERR_FAIL_COND_V(check_error(png_img), ERR_FILE_CORRUPT); + ERR_FAIL_COND_V(!success, ERR_FILE_CORRUPT); + + p_image->create(png_img.width, png_img.height, 0, dest_format, buffer); + + return OK; +} + +Error image_to_png(const Ref<Image> &p_image, PoolVector<uint8_t> &p_buffer) { + + Ref<Image> source_image = p_image->duplicate(); + + if (source_image->is_compressed()) + source_image->decompress(); + + ERR_FAIL_COND_V(source_image->is_compressed(), FAILED); + + png_image png_img; + zeromem(&png_img, sizeof(png_img)); + png_img.version = PNG_IMAGE_VERSION; + png_img.width = source_image->get_width(); + png_img.height = source_image->get_height(); + + switch (source_image->get_format()) { + case Image::FORMAT_L8: + png_img.format = PNG_FORMAT_GRAY; + break; + case Image::FORMAT_LA8: + png_img.format = PNG_FORMAT_GA; + break; + case Image::FORMAT_RGB8: + png_img.format = PNG_FORMAT_RGB; + break; + case Image::FORMAT_RGBA8: + png_img.format = PNG_FORMAT_RGBA; + break; + default: + if (source_image->detect_alpha()) { + source_image->convert(Image::FORMAT_RGBA8); + png_img.format = PNG_FORMAT_RGBA; + } else { + source_image->convert(Image::FORMAT_RGB8); + png_img.format = PNG_FORMAT_RGB; + } + } + + const PoolVector<uint8_t> image_data = source_image->get_data(); + const PoolVector<uint8_t>::Read reader = image_data.read(); + + // we may be passed a buffer with existing content we're expected to append to + const int buffer_offset = p_buffer.size(); + + const size_t png_size_estimate = PNG_IMAGE_PNG_SIZE_MAX(png_img); + + // try with estimated size + size_t compressed_size = png_size_estimate; + int success = 0; + { // scope writer lifetime + Error err = p_buffer.resize(buffer_offset + png_size_estimate); + ERR_FAIL_COND_V(err, err); + + PoolVector<uint8_t>::Write writer = p_buffer.write(); + success = png_image_write_to_memory(&png_img, &writer[buffer_offset], + &compressed_size, 0, reader.ptr(), 0, NULL); + ERR_FAIL_COND_V(check_error(png_img), FAILED); + } + if (!success) { + + // buffer was big enough, must be some other error + ERR_FAIL_COND_V(compressed_size <= png_size_estimate, FAILED); + + // write failed due to buffer size, resize and retry + Error err = p_buffer.resize(buffer_offset + compressed_size); + ERR_FAIL_COND_V(err, err); + + PoolVector<uint8_t>::Write writer = p_buffer.write(); + success = png_image_write_to_memory(&png_img, &writer[buffer_offset], + &compressed_size, 0, reader.ptr(), 0, NULL); + ERR_FAIL_COND_V(check_error(png_img), FAILED); + ERR_FAIL_COND_V(!success, FAILED); + } + + // trim buffer size to content + Error err = p_buffer.resize(buffer_offset + compressed_size); + ERR_FAIL_COND_V(err, err); + + return OK; +} + +} // namespace PNGDriverCommon diff --git a/drivers/gl_context/context_gl.cpp b/drivers/png/png_driver_common.h index aa36658698..3ff87759fb 100644 --- a/drivers/gl_context/context_gl.cpp +++ b/drivers/png/png_driver_common.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* context_gl.cpp */ +/* png_driver_common.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -28,28 +28,21 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ -#include "context_gl.h" +#ifndef PNG_DRIVER_COMMON_H +#define PNG_DRIVER_COMMON_H -#if defined(OPENGL_ENABLED) || defined(GLES_ENABLED) +#include "core/image.h" +#include "core/pool_vector.h" -ContextGL *ContextGL::singleton = NULL; +namespace PNGDriverCommon { -ContextGL *ContextGL::get_singleton() { +// Attempt to load png from buffer (p_source, p_size) into p_image +Error png_to_image(const uint8_t *p_source, size_t p_size, Ref<Image> p_image); - return singleton; -} +// Append p_image, as a png, to p_buffer. +// Contents of p_buffer is unspecified if error returned. +Error image_to_png(const Ref<Image> &p_image, PoolVector<uint8_t> &p_buffer); -ContextGL::ContextGL() { - - ERR_FAIL_COND(singleton); - - singleton = this; -} - -ContextGL::~ContextGL() { - - if (singleton == this) - singleton = NULL; -} +} // namespace PNGDriverCommon #endif diff --git a/drivers/png/resource_saver_png.cpp b/drivers/png/resource_saver_png.cpp index c5729f70b2..3b3f1506dc 100644 --- a/drivers/png/resource_saver_png.cpp +++ b/drivers/png/resource_saver_png.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -32,152 +32,41 @@ #include "core/image.h" #include "core/os/file_access.h" -#include "core/project_settings.h" +#include "drivers/png/png_driver_common.h" #include "scene/resources/texture.h" -#include <png.h> - -static void _write_png_data(png_structp png_ptr, png_bytep data, png_size_t p_length) { - - FileAccess *f = (FileAccess *)png_get_io_ptr(png_ptr); - f->store_buffer((const uint8_t *)data, p_length); -} - Error ResourceSaverPNG::save(const String &p_path, const RES &p_resource, uint32_t p_flags) { Ref<ImageTexture> texture = p_resource; - ERR_FAIL_COND_V(!texture.is_valid(), ERR_INVALID_PARAMETER); - ERR_EXPLAIN("Can't save empty texture as PNG"); - ERR_FAIL_COND_V(!texture->get_width() || !texture->get_height(), ERR_INVALID_PARAMETER); + ERR_FAIL_COND_V_MSG(!texture.is_valid(), ERR_INVALID_PARAMETER, "Can't save invalid texture as PNG."); + ERR_FAIL_COND_V_MSG(!texture->get_width(), ERR_INVALID_PARAMETER, "Can't save empty texture as PNG."); Ref<Image> img = texture->get_data(); Error err = save_image(p_path, img); - if (err == OK) { - } - return err; }; Error ResourceSaverPNG::save_image(const String &p_path, const Ref<Image> &p_img) { - Ref<Image> img = p_img->duplicate(); - - if (img->is_compressed()) - img->decompress(); - - ERR_FAIL_COND_V(img->is_compressed(), ERR_INVALID_PARAMETER); - - png_structp png_ptr; - png_infop info_ptr; - png_bytep *row_pointers; - - /* initialize stuff */ - png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); - - ERR_FAIL_COND_V(!png_ptr, ERR_CANT_CREATE); + PoolVector<uint8_t> buffer; + Error err = PNGDriverCommon::image_to_png(p_img, buffer); + ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG."); + FileAccess *file = FileAccess::open(p_path, FileAccess::WRITE, &err); + ERR_FAIL_COND_V_MSG(err, err, vformat("Can't save PNG at path: '%s'.", p_path)); - info_ptr = png_create_info_struct(png_ptr); + PoolVector<uint8_t>::Read reader = buffer.read(); - ERR_FAIL_COND_V(!info_ptr, ERR_CANT_CREATE); - - if (setjmp(png_jmpbuf(png_ptr))) { - ERR_FAIL_V(ERR_CANT_OPEN); - } - //change this - Error err; - FileAccess *f = FileAccess::open(p_path, FileAccess::WRITE, &err); - if (err) { - ERR_FAIL_V(err); - } - - png_set_write_fn(png_ptr, f, _write_png_data, NULL); - - /* write header */ - if (setjmp(png_jmpbuf(png_ptr))) { - ERR_FAIL_V(ERR_CANT_OPEN); + file->store_buffer(reader.ptr(), buffer.size()); + if (file->get_error() != OK && file->get_error() != ERR_FILE_EOF) { + memdelete(file); + return ERR_CANT_CREATE; } - int pngf = 0; - int cs = 0; - - switch (img->get_format()) { - - case Image::FORMAT_L8: { - - pngf = PNG_COLOR_TYPE_GRAY; - cs = 1; - } break; - case Image::FORMAT_LA8: { - - pngf = PNG_COLOR_TYPE_GRAY_ALPHA; - cs = 2; - } break; - case Image::FORMAT_RGB8: { - - pngf = PNG_COLOR_TYPE_RGB; - cs = 3; - } break; - case Image::FORMAT_RGBA8: { - - pngf = PNG_COLOR_TYPE_RGB_ALPHA; - cs = 4; - } break; - default: { - - if (img->detect_alpha()) { - - img->convert(Image::FORMAT_RGBA8); - pngf = PNG_COLOR_TYPE_RGB_ALPHA; - cs = 4; - } else { - - img->convert(Image::FORMAT_RGB8); - pngf = PNG_COLOR_TYPE_RGB; - cs = 3; - } - } - } - - int w = img->get_width(); - int h = img->get_height(); - png_set_IHDR(png_ptr, info_ptr, w, h, - 8, pngf, PNG_INTERLACE_NONE, - PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); - - png_write_info(png_ptr, info_ptr); - - /* write bytes */ - if (setjmp(png_jmpbuf(png_ptr))) { - memdelete(f); - ERR_FAIL_V(ERR_CANT_OPEN); - } - - PoolVector<uint8_t>::Read r = img->get_data().read(); - - row_pointers = (png_bytep *)memalloc(sizeof(png_bytep) * h); - for (int i = 0; i < h; i++) { - - row_pointers[i] = (png_bytep)&r[i * w * cs]; - } - png_write_image(png_ptr, row_pointers); - - memfree(row_pointers); - - /* end write */ - if (setjmp(png_jmpbuf(png_ptr))) { - - memdelete(f); - ERR_FAIL_V(ERR_CANT_OPEN); - } - - png_write_end(png_ptr, NULL); - memdelete(f); - - /* cleanup heap allocation */ - png_destroy_write_struct(&png_ptr, &info_ptr); + file->close(); + memdelete(file); return OK; } @@ -186,9 +75,10 @@ bool ResourceSaverPNG::recognize(const RES &p_resource) const { return (p_resource.is_valid() && p_resource->is_class("ImageTexture")); } + void ResourceSaverPNG::get_recognized_extensions(const RES &p_resource, List<String> *p_extensions) const { - if (Object::cast_to<Texture>(*p_resource)) { + if (Object::cast_to<ImageTexture>(*p_resource)) { p_extensions->push_back("png"); } } diff --git a/drivers/png/resource_saver_png.h b/drivers/png/resource_saver_png.h index 34950f6723..9267f2d678 100644 --- a/drivers/png/resource_saver_png.h +++ b/drivers/png/resource_saver_png.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ 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 7578fbc0a0..7ba2175652 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -43,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; } } @@ -188,6 +191,14 @@ Error AudioDriverPulseAudio::init_device() { spec.format = PA_SAMPLE_S16LE; spec.channels = pa_map.channels; spec.rate = mix_rate; + pa_map.map[0] = PA_CHANNEL_POSITION_FRONT_LEFT; + pa_map.map[1] = PA_CHANNEL_POSITION_FRONT_RIGHT; + pa_map.map[2] = PA_CHANNEL_POSITION_FRONT_CENTER; + pa_map.map[3] = PA_CHANNEL_POSITION_LFE; + pa_map.map[4] = PA_CHANNEL_POSITION_REAR_LEFT; + pa_map.map[5] = PA_CHANNEL_POSITION_REAR_RIGHT; + pa_map.map[6] = PA_CHANNEL_POSITION_SIDE_LEFT; + pa_map.map[7] = PA_CHANNEL_POSITION_SIDE_RIGHT; pa_str = pa_stream_new(pa_ctx, "Sound", &spec, &pa_map); if (pa_str == NULL) { @@ -216,8 +227,8 @@ Error AudioDriverPulseAudio::init_device() { samples_out.resize(pa_buffer_size); // Reset audio input to keep synchronisation. - input_position = 0; - input_size = 0; + capture_position = 0; + capture_size = 0; return OK; } @@ -255,7 +266,10 @@ Error AudioDriverPulseAudio::init() { } while (pa_ready == 0) { - pa_mainloop_iterate(pa_ml, 1, NULL); + ret = pa_mainloop_iterate(pa_ml, 1, NULL); + if (ret < 0) { + ERR_PRINT("pa_mainloop_iterate error"); + } } if (pa_ready < 0) { @@ -313,6 +327,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)p_udata; unsigned int write_ofs = 0; size_t avail_bytes = 0; + uint32_t default_device_msec = OS::get_singleton()->get_ticks_msec(); while (!ad->exit_thread) { @@ -340,12 +355,12 @@ 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++]; - uint32_t r = ad->samples_in[in_idx++]; - ad->samples_out.write[out_idx++] = ((l >> 1) + (r >> 1)) >> 16; + uint32_t l = ad->samples_in[in_idx++] >> 16; + uint32_t r = ad->samples_in[in_idx++] >> 16; + ad->samples_out.write[out_idx++] = (l + r) / 2; } } } @@ -371,7 +386,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { const void *ptr = ad->samples_out.ptr(); ret = pa_stream_write(ad->pa_str, (char *)ptr + write_ofs, bytes_to_write, NULL, 0LL, PA_SEEK_RELATIVE); if (ret != 0) { - ERR_PRINT("pa_stream_write error"); + ERR_PRINTS("PulseAudio: pa_stream_write error: " + String(pa_strerror(ret))); } else { avail_bytes -= bytes_to_write; write_ofs += bytes_to_write; @@ -398,13 +413,57 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { break; } } + + avail_bytes = 0; + write_ofs = 0; + } + + // If we're using the default device check that the current device is still the default + if (ad->device_name == "Default") { + + uint32_t msec = OS::get_singleton()->get_ticks_msec(); + if (msec > (default_device_msec + 1000)) { + String old_default_device = ad->default_device; + + default_device_msec = msec; + + ad->pa_status = 0; + pa_operation *pa_op = pa_context_get_server_info(ad->pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)ad); + if (pa_op) { + while (ad->pa_status == 0) { + ret = pa_mainloop_iterate(ad->pa_ml, 1, NULL); + if (ret < 0) { + ERR_PRINT("pa_mainloop_iterate error"); + } + } + + pa_operation_unref(pa_op); + } else { + ERR_PRINT("pa_context_get_server_info error"); + } + + if (old_default_device != ad->default_device) { + ad->finish_device(); + + Error err = ad->init_device(); + if (err != OK) { + ERR_PRINT("PulseAudio: init_device error"); + ad->active = false; + ad->exit_thread = true; + break; + } + + avail_bytes = 0; + write_ofs = 0; + } + } } if (ad->pa_rec_str && pa_stream_get_state(ad->pa_rec_str) == PA_STREAM_READY) { size_t bytes = pa_stream_readable_size(ad->pa_rec_str); if (bytes > 0) { const void *ptr = NULL; - size_t maxbytes = ad->input_buffer.size() * sizeof(int16_t); + size_t maxbytes = ad->capture_buffer.size() * sizeof(int16_t); bytes = MIN(bytes, maxbytes); ret = pa_stream_peek(ad->pa_rec_str, &ptr, &bytes); @@ -414,11 +473,11 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { int16_t *srcptr = (int16_t *)ptr; for (size_t i = bytes >> 1; i > 0; i--) { int32_t sample = int32_t(*srcptr++) << 16; - ad->input_buffer_write(sample); + ad->capture_buffer_write(sample); if (ad->pa_rec_map.channels == 1) { - // In case input device is single channel convert it to Stereo - ad->input_buffer_write(sample); + // In case capture device is single channel convert it to Stereo + ad->capture_buffer_write(sample); } } @@ -605,25 +664,23 @@ Error AudioDriverPulseAudio::capture_init_device() { break; default: - WARN_PRINTS("PulseAudio: Unsupported number of input channels: " + itos(pa_rec_map.channels)); + WARN_PRINTS("PulseAudio: Unsupported number of capture channels: " + itos(pa_rec_map.channels)); pa_channel_map_init_stereo(&pa_rec_map); 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) { @@ -639,9 +696,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; + capture_buffer_init(input_buffer_frames); + + print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " capture channels"); + print_verbose("PulseAudio: capture buffer frames: " + itos(input_buffer_frames) + " calculated latency: " + itos(input_buffer_frames * 1000 / mix_rate) + "ms"); return OK; } @@ -738,36 +796,28 @@ String AudioDriverPulseAudio::capture_get_device() { return name; } -AudioDriverPulseAudio::AudioDriverPulseAudio() { - - pa_ml = NULL; - pa_ctx = NULL; - pa_str = NULL; - pa_rec_str = NULL; - - mutex = NULL; - thread = NULL; - - device_name = "Default"; - new_device = "Default"; - default_device = ""; - +AudioDriverPulseAudio::AudioDriverPulseAudio() : + thread(NULL), + mutex(NULL), + pa_ml(NULL), + pa_ctx(NULL), + pa_str(NULL), + pa_rec_str(NULL), + device_name("Default"), + new_device("Default"), + default_device(""), + mix_rate(0), + buffer_frames(0), + pa_buffer_size(0), + channels(0), + pa_ready(0), + pa_status(0), + active(false), + thread_exited(false), + exit_thread(false), + latency(0) { samples_in.clear(); samples_out.clear(); - - mix_rate = 0; - buffer_frames = 0; - input_buffer_frames = 0; - pa_buffer_size = 0; - channels = 0; - pa_ready = 0; - pa_status = 0; - - active = false; - thread_exited = false; - exit_thread = false; - - latency = 0; } AudioDriverPulseAudio::~AudioDriverPulseAudio() { diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index f8358a452b..caa09d6020 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -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..20556d98af 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -31,26 +31,26 @@ #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 #include "platform/windows/export/export.h" #endif -static ImageLoaderPNG *image_loader_png = NULL; -static ResourceSaverPNG *resource_saver_png = NULL; +static ImageLoaderPNG *image_loader_png; +static Ref<ResourceSaverPNG> resource_saver_png; void register_core_driver_types() { image_loader_png = memnew(ImageLoaderPNG); ImageLoader::add_image_format_loader(image_loader_png); - resource_saver_png = memnew(ResourceSaverPNG); + resource_saver_png.instance(); ResourceSaver::add_resource_format_saver(resource_saver_png); } @@ -58,8 +58,9 @@ void unregister_core_driver_types() { if (image_loader_png) memdelete(image_loader_png); - if (resource_saver_png) - memdelete(resource_saver_png); + + ResourceSaver::remove_resource_format_saver(resource_saver_png); + resource_saver_png.unref(); } void register_driver_types() { diff --git a/drivers/register_driver_types.h b/drivers/register_driver_types.h index ddd1fac093..a3398964dd 100644 --- a/drivers/register_driver_types.h +++ b/drivers/register_driver_types.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -31,10 +31,6 @@ #ifndef REGISTER_DRIVER_TYPES_H #define REGISTER_DRIVER_TYPES_H -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - void register_core_driver_types(); void unregister_core_driver_types(); diff --git a/drivers/rtaudio/SCsub b/drivers/rtaudio/SCsub deleted file mode 100644 index 2b0a602965..0000000000 --- a/drivers/rtaudio/SCsub +++ /dev/null @@ -1,20 +0,0 @@ -#!/usr/bin/env python - -Import('env') - -# Not cloning the env, the includes need to be accessible for platform/ - -# Thirdparty source files -thirdparty_dir = "#thirdparty/rtaudio/" -thirdparty_sources = [ - "RtAudio.cpp", -] -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -env.add_source_files(env.drivers_sources, thirdparty_sources) -env.Append(CPPPATH=[thirdparty_dir]) - -# Driver source files -env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp deleted file mode 100644 index 10ba0663f2..0000000000 --- a/drivers/rtaudio/audio_driver_rtaudio.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/*************************************************************************/ -/* audio_driver_rtaudio.cpp */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#include "audio_driver_rtaudio.h" - -#include "core/os/os.h" -#include "core/project_settings.h" - -#ifdef RTAUDIO_ENABLED - -const char *AudioDriverRtAudio::get_name() const { - -#ifdef OSX_ENABLED - return "RtAudio-OSX"; -#elif defined(UNIX_ENABLED) - return "RtAudio-ALSA"; -#elif defined(WINDOWS_ENABLED) - return "RtAudio-DirectSound"; -#else - return "RtAudio-None"; -#endif -} - -int AudioDriverRtAudio::callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, double streamTime, RtAudioStreamStatus status, void *userData) { - - if (status) { - if (status & RTAUDIO_INPUT_OVERFLOW) { - WARN_PRINT("RtAudio input overflow!"); - } - if (status & RTAUDIO_OUTPUT_UNDERFLOW) { - WARN_PRINT("RtAudio output underflow!"); - } - } - int32_t *buffer = (int32_t *)outputBuffer; - - AudioDriverRtAudio *self = (AudioDriverRtAudio *)userData; - - if (self->mutex->try_lock() != OK) { - // what should i do.. - for (unsigned int i = 0; i < nBufferFrames; i++) - buffer[i] = 0; - - return 0; - } - - self->audio_server_process(nBufferFrames, buffer); - - self->mutex->unlock(); - - return 0; -} - -Error AudioDriverRtAudio::init() { - - active = false; - mutex = Mutex::create(true); - dac = memnew(RtAudio); - - ERR_EXPLAIN("Cannot initialize RtAudio audio driver: No devices present.") - ERR_FAIL_COND_V(dac->getDeviceCount() < 1, ERR_UNAVAILABLE); - - // FIXME: Adapt to the OutputFormat -> SpeakerMode change - /* - String channels = GLOBAL_DEF_RST("audio/output","stereo"); - - if (channels=="5.1") - output_format=OUTPUT_5_1; - else if (channels=="quad") - output_format=OUTPUT_QUAD; - else if (channels=="mono") - output_format=OUTPUT_MONO; - else - output_format=OUTPUT_STEREO; - */ - - RtAudio::StreamParameters parameters; - parameters.deviceId = dac->getDefaultOutputDevice(); - RtAudio::StreamOptions options; - - // set the desired numberOfBuffers - options.numberOfBuffers = 4; - - parameters.firstChannel = 0; - mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); - - int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY); - 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; - - while (tries >= 0) { - switch (speaker_mode) { - case SPEAKER_MODE_STEREO: parameters.nChannels = 2; break; - case SPEAKER_SURROUND_51: parameters.nChannels = 6; break; - case SPEAKER_SURROUND_71: parameters.nChannels = 8; break; - }; - - try { - dac->openStream(¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_frames, &callback, this, &options); - active = true; - - break; - } catch (RtAudioError &e) { - // 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_SURROUND_71: speaker_mode = SPEAKER_SURROUND_51; break; - } - - tries--; - } - } - - return active ? OK : ERR_UNAVAILABLE; -} - -int AudioDriverRtAudio::get_mix_rate() const { - - return mix_rate; -} - -AudioDriver::SpeakerMode AudioDriverRtAudio::get_speaker_mode() const { - - return speaker_mode; -} - -void AudioDriverRtAudio::start() { - - if (active) - dac->startStream(); -} - -void AudioDriverRtAudio::lock() { - - if (mutex) - mutex->lock(); -} - -void AudioDriverRtAudio::unlock() { - - if (mutex) - mutex->unlock(); -} - -void AudioDriverRtAudio::finish() { - - lock(); - if (active && dac->isStreamOpen()) { - dac->closeStream(); - active = false; - } - unlock(); - - if (mutex) { - memdelete(mutex); - mutex = NULL; - } - if (dac) { - memdelete(dac); - dac = NULL; - } -} - -AudioDriverRtAudio::AudioDriverRtAudio() { - - active = false; - mutex = NULL; - dac = NULL; - mix_rate = DEFAULT_MIX_RATE; - speaker_mode = SPEAKER_MODE_STEREO; -} - -#endif diff --git a/drivers/rtaudio/audio_driver_rtaudio.h b/drivers/rtaudio/audio_driver_rtaudio.h deleted file mode 100644 index 2a64652d5f..0000000000 --- a/drivers/rtaudio/audio_driver_rtaudio.h +++ /dev/null @@ -1,65 +0,0 @@ -/*************************************************************************/ -/* audio_driver_rtaudio.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 AUDIO_DRIVER_RTAUDIO_H -#define AUDIO_DRIVER_RTAUDIO_H - -#ifdef RTAUDIO_ENABLED - -#include "servers/audio_server.h" - -#include <RtAudio.h> - -class AudioDriverRtAudio : public AudioDriver { - - static int callback(void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, - double streamTime, RtAudioStreamStatus status, void *userData); - SpeakerMode speaker_mode; - Mutex *mutex; - RtAudio *dac; - int mix_rate; - bool active; - -public: - virtual const char *get_name() const; - - virtual Error init(); - virtual void start(); - virtual int get_mix_rate() const; - virtual SpeakerMode get_speaker_mode() const; - virtual void lock(); - virtual void unlock(); - virtual void finish(); - - AudioDriverRtAudio(); -}; - -#endif // AUDIO_DRIVER_RTAUDIO_H -#endif 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 a5a9258c4a..6817137a94 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -100,10 +100,7 @@ bool DirAccessUnix::dir_exists(String p_dir) { struct stat flags; bool success = (stat(p_dir.utf8().get_data(), &flags) == 0); - if (success && S_ISDIR(flags.st_mode)) - return true; - - return false; + return (success && S_ISDIR(flags.st_mode)); } uint64_t DirAccessUnix::get_modified_time(String p_file) { @@ -129,37 +126,32 @@ String DirAccessUnix::get_next() { if (!dir_stream) return ""; - dirent *entry; - entry = readdir(dir_stream); + dirent *entry = readdir(dir_stream); if (entry == NULL) { - list_dir_end(); return ""; } - //typedef struct stat Stat; - struct stat flags; - String fname = fix_unicode_name(entry->d_name); - String f = current_dir.plus_file(fname); - - if (stat(f.utf8().get_data(), &flags) == 0) { - - if (S_ISDIR(flags.st_mode)) { - - _cisdir = true; - + // Look at d_type to determine if the entry is a directory, unless + // its type is unknown (the file system does not support it) or if + // the type is a link, in that case we want to resolve the link to + // known if it points to a directory. stat() will resolve the link + // for us. + if (entry->d_type == DT_UNKNOWN || entry->d_type == DT_LNK) { + String f = current_dir.plus_file(fname); + + struct stat flags; + if (stat(f.utf8().get_data(), &flags) == 0) { + _cisdir = S_ISDIR(flags.st_mode); } else { - _cisdir = false; } - } else { - - _cisdir = false; + _cisdir = (entry->d_type == DT_DIR); } _cishidden = (fname != "." && fname != ".." && fname.begins_with(".")); @@ -309,14 +301,14 @@ 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? // try_dir is the directory we are trying to change into String try_dir = ""; if (p_dir.is_rel_path()) { - String next_dir = current_dir + "/" + p_dir; + String next_dir = current_dir.plus_file(p_dir); next_dir = next_dir.simplify_path(); try_dir = next_dir; } else { @@ -328,9 +320,20 @@ Error DirAccessUnix::change_dir(String p_dir) { return ERR_INVALID_PARAMETER; } + String base = _get_root_path(); + if (base != String() && !try_dir.begins_with(base)) { + ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG); + String new_dir; + new_dir.parse_utf8(real_current_dir_name); + + if (!new_dir.begins_with(base)) { + try_dir = current_dir; //revert + } + } + // 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; } @@ -391,11 +394,15 @@ size_t DirAccessUnix::get_space_left() { return vfs.f_bfree * vfs.f_bsize; #else -#warning THIS IS BROKEN + // FIXME: Implement this. return 0; #endif }; +String DirAccessUnix::get_filesystem_type() const { + return ""; //TODO this should be implemented +} + DirAccessUnix::DirAccessUnix() { dir_stream = 0; @@ -405,7 +412,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 26978930bd..88674d2769 100644 --- a/drivers/unix/dir_access_unix.h +++ b/drivers/unix/dir_access_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -40,10 +40,6 @@ #include <sys/types.h> #include <unistd.h> -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class DirAccessUnix : public DirAccess { DIR *dir_stream; @@ -82,6 +78,8 @@ public: virtual size_t get_space_left(); + virtual String get_filesystem_type() const; + DirAccessUnix(); ~DirAccessUnix(); }; diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index 3b97b95f7c..8be1d5d8f3 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -38,6 +38,8 @@ #include <sys/stat.h> #include <sys/types.h> +#include <errno.h> + #if defined(UNIX_ENABLED) #include <unistd.h> #endif @@ -56,7 +58,7 @@ void FileAccessUnix::check_errors() const { - ERR_FAIL_COND(!f); + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); if (feof(f)) { @@ -74,7 +76,7 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { path = fix_path(p_path); //printf("opening %ls, %i\n", path.c_str(), Memory::get_static_mem_usage()); - ERR_FAIL_COND_V(f, ERR_ALREADY_IN_USE); + ERR_FAIL_COND_V_MSG(f, ERR_ALREADY_IN_USE, "File is already in use."); const char *mode_string; if (p_mode_flags == READ) @@ -112,8 +114,15 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { f = fopen(path.utf8().get_data(), mode_string); if (f == NULL) { - last_error = ERR_FILE_CANT_OPEN; - return ERR_FILE_CANT_OPEN; + switch (errno) { + case ENOENT: { + last_error = ERR_FILE_NOT_FOUND; + } break; + default: { + last_error = ERR_FILE_CANT_OPEN; + } break; + } + return last_error; } else { last_error = OK; flags = p_mode_flags; @@ -162,7 +171,7 @@ String FileAccessUnix::get_path_absolute() const { void FileAccessUnix::seek(size_t p_position) { - ERR_FAIL_COND(!f); + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); last_error = OK; if (fseek(f, p_position, SEEK_SET)) @@ -171,7 +180,7 @@ void FileAccessUnix::seek(size_t p_position) { void FileAccessUnix::seek_end(int64_t p_position) { - ERR_FAIL_COND(!f); + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); if (fseek(f, p_position, SEEK_END)) check_errors(); @@ -179,7 +188,7 @@ void FileAccessUnix::seek_end(int64_t p_position) { size_t FileAccessUnix::get_position() const { - ERR_FAIL_COND_V(!f, 0); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); long pos = ftell(f); if (pos < 0) { @@ -191,7 +200,7 @@ size_t FileAccessUnix::get_position() const { size_t FileAccessUnix::get_len() const { - ERR_FAIL_COND_V(!f, 0); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); long pos = ftell(f); ERR_FAIL_COND_V(pos < 0, 0); @@ -210,7 +219,7 @@ bool FileAccessUnix::eof_reached() const { uint8_t FileAccessUnix::get_8() const { - ERR_FAIL_COND_V(!f, 0); + ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use."); uint8_t b; if (fread(&b, 1, 1, f) == 0) { check_errors(); @@ -221,7 +230,7 @@ uint8_t FileAccessUnix::get_8() const { int FileAccessUnix::get_buffer(uint8_t *p_dst, int p_length) const { - ERR_FAIL_COND_V(!f, -1); + ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use."); int read = fread(p_dst, 1, p_length, f); check_errors(); return read; @@ -234,19 +243,20 @@ Error FileAccessUnix::get_error() const { void FileAccessUnix::flush() { - ERR_FAIL_COND(!f); + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); fflush(f); } void FileAccessUnix::store_8(uint8_t p_dest) { - ERR_FAIL_COND(!f); + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1); } void FileAccessUnix::store_buffer(const uint8_t *p_src, int p_length) { - ERR_FAIL_COND(!f); - ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); + + ERR_FAIL_COND_MSG(!f, "File must be opened before use."); + ERR_FAIL_COND((int)fwrite(p_src, 1, p_length, f) != p_length); } bool FileAccessUnix::file_exists(const String &p_path) { @@ -288,13 +298,28 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) { if (!err) { return flags.st_mtime; } else { - ERR_EXPLAIN("Failed to get modified time for: " + p_file); - ERR_FAIL_V(0); + ERR_FAIL_V_MSG(0, "Failed to get modified time for: " + p_file + "."); + }; +} + +uint32_t FileAccessUnix::_get_unix_permissions(const String &p_file) { + + String file = fix_path(p_file); + struct stat flags; + int err = stat(file.utf8().get_data(), &flags); + + if (!err) { + return flags.st_mode & 0x7FF; //only permissions + } else { + ERR_FAIL_V_MSG(0, "Failed to get unix permissions for: " + p_file + "."); }; } -Error FileAccessUnix::_chmod(const String &p_path, int p_mod) { - int err = chmod(p_path.utf8().get_data(), p_mod); +Error FileAccessUnix::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + + String file = fix_path(p_file); + + int err = chmod(file.utf8().get_data(), p_permissions); if (!err) { return OK; } @@ -309,11 +334,10 @@ FileAccess *FileAccessUnix::create_libc() { CloseNotificationFunc FileAccessUnix::close_notification_func = NULL; -FileAccessUnix::FileAccessUnix() { - - f = NULL; - flags = 0; - last_error = OK; +FileAccessUnix::FileAccessUnix() : + f(NULL), + flags(0), + last_error(OK) { } FileAccessUnix::~FileAccessUnix() { diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index d4a4f8230c..e26591e3e8 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -38,10 +38,6 @@ #if defined(UNIX_ENABLED) || defined(LIBC_FILEIO_ENABLED) -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - typedef void (*CloseNotificationFunc)(const String &p_file, int p_flags); class FileAccessUnix : public FileAccess { @@ -85,8 +81,8 @@ public: virtual bool file_exists(const String &p_path); ///< return true if a file exists virtual uint64_t _get_modified_time(const String &p_file); - - virtual Error _chmod(const String &p_path, int p_mod); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); FileAccessUnix(); virtual ~FileAccessUnix(); diff --git a/drivers/unix/ip_unix.cpp b/drivers/unix/ip_unix.cpp index 949609bb9a..cf47cdc7e8 100644 --- a/drivers/unix/ip_unix.cpp +++ b/drivers/unix/ip_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -50,15 +50,17 @@ #define _WIN32_WINNT 0x0501 // Windows XP, disable Vista API #include <iphlpapi.h> #undef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 // Reenable Vista API +#define _WIN32_WINNT 0x0600 // Re-enable Vista API #else #include <iphlpapi.h> #endif // MINGW hack #endif -#else +#else // UNIX #include <netdb.h> #ifdef ANDROID_ENABLED -#include "platform/android/ifaddrs_android.h" +// We could drop this file once we up our API level to 24, +// where the NDK's ifaddrs.h supports to needed getifaddrs. +#include "thirdparty/misc/ifaddrs-android.h" #else #ifdef __FreeBSD__ #include <sys/types.h> @@ -70,11 +72,13 @@ #ifdef __FreeBSD__ #include <netinet/in.h> #endif +#include <net/if.h> // Order is important on OpenBSD, leave as last #endif static IP_Address _sockaddr2ip(struct sockaddr *p_addr) { IP_Address ip; + if (p_addr->sa_family == AF_INET) { struct sockaddr_in *addr = (struct sockaddr_in *)p_addr; ip.set_ipv4((uint8_t *)&(addr->sin_addr)); @@ -127,24 +131,42 @@ IP_Address IP_Unix::_resolve_hostname(const String &p_hostname, Type p_type) { #if defined(UWP_ENABLED) -void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { +void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { using namespace Windows::Networking; using namespace Windows::Networking::Connectivity; + // Returns addresses, not interfaces. auto hostnames = NetworkInformation::GetHostNames(); for (int i = 0; i < hostnames->Size; i++) { - if (hostnames->GetAt(i)->Type == HostNameType::Ipv4 || hostnames->GetAt(i)->Type == HostNameType::Ipv6 && hostnames->GetAt(i)->IPInformation != nullptr) { + auto hostname = hostnames->GetAt(i); + + if (hostname->Type != HostNameType::Ipv4 && hostname->Type != HostNameType::Ipv6) + continue; - r_addresses->push_back(IP_Address(String(hostnames->GetAt(i)->CanonicalName->Data()))); + String name = hostname->RawName->Data(); + Map<String, Interface_Info>::Element *E = r_interfaces->find(name); + if (!E) { + Interface_Info info; + info.name = name; + info.name_friendly = hostname->DisplayName->Data(); + info.index = String::num_uint64(0); + E = r_interfaces->insert(name, info); + ERR_CONTINUE(!E); } + + Interface_Info &info = E->get(); + + IP_Address ip = IP_Address(hostname->CanonicalName->Data()); + info.ip_addresses.push_front(ip); } -}; +} + #else -void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { +void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { ULONG buf_size = 1024; IP_ADAPTER_ADDRESSES *addrs; @@ -162,38 +184,30 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { continue; // will go back and alloc the right size }; - ERR_EXPLAIN("Call to GetAdaptersAddresses failed with error " + itos(err)); - ERR_FAIL(); - return; + ERR_FAIL_MSG("Call to GetAdaptersAddresses failed with error " + itos(err) + "."); }; IP_ADAPTER_ADDRESSES *adapter = addrs; while (adapter != NULL) { + Interface_Info info; + info.name = adapter->AdapterName; + info.name_friendly = adapter->FriendlyName; + info.index = String::num_uint64(adapter->IfIndex); + IP_ADAPTER_UNICAST_ADDRESS *address = adapter->FirstUnicastAddress; while (address != NULL) { - - IP_Address ip; - - if (address->Address.lpSockaddr->sa_family == AF_INET) { - - SOCKADDR_IN *ipv4 = reinterpret_cast<SOCKADDR_IN *>(address->Address.lpSockaddr); - - ip.set_ipv4((uint8_t *)&(ipv4->sin_addr)); - r_addresses->push_back(ip); - - } else if (address->Address.lpSockaddr->sa_family == AF_INET6) { // ipv6 - - SOCKADDR_IN6 *ipv6 = reinterpret_cast<SOCKADDR_IN6 *>(address->Address.lpSockaddr); - - ip.set_ipv6(ipv6->sin6_addr.s6_addr); - r_addresses->push_back(ip); - }; - + int family = address->Address.lpSockaddr->sa_family; + if (family != AF_INET && family != AF_INET6) + continue; + info.ip_addresses.push_front(_sockaddr2ip(address->Address.lpSockaddr)); address = address->Next; - }; + } adapter = adapter->Next; + // Only add interface if it has at least one IP + if (info.ip_addresses.size() > 0) + r_interfaces->insert(info.name, info); }; memfree(addrs); @@ -201,9 +215,9 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { #endif -#else +#else // UNIX -void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { +void IP_Unix::get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const { struct ifaddrs *ifAddrStruct = NULL; struct ifaddrs *ifa = NULL; @@ -220,8 +234,18 @@ void IP_Unix::get_local_addresses(List<IP_Address> *r_addresses) const { if (family != AF_INET && family != AF_INET6) continue; - IP_Address ip = _sockaddr2ip(ifa->ifa_addr); - r_addresses->push_back(ip); + Map<String, Interface_Info>::Element *E = r_interfaces->find(ifa->ifa_name); + if (!E) { + Interface_Info info; + info.name = ifa->ifa_name; + info.name_friendly = ifa->ifa_name; + info.index = String::num_uint64(if_nametoindex(ifa->ifa_name)); + E = r_interfaces->insert(ifa->ifa_name, info); + ERR_CONTINUE(!E); + } + + Interface_Info &info = E->get(); + info.ip_addresses.push_front(_sockaddr2ip(ifa->ifa_addr)); } if (ifAddrStruct != NULL) freeifaddrs(ifAddrStruct); diff --git a/drivers/unix/ip_unix.h b/drivers/unix/ip_unix.h index 83535045b1..f9bb626cc4 100644 --- a/drivers/unix/ip_unix.h +++ b/drivers/unix/ip_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -43,7 +43,7 @@ class IP_Unix : public IP { static IP *_create_unix(); public: - virtual void get_local_addresses(List<IP_Address> *r_addresses) const; + virtual void get_local_interfaces(Map<String, Interface_Info> *r_interfaces) const; static void make_default(); IP_Unix(); diff --git a/drivers/unix/mutex_posix.cpp b/drivers/unix/mutex_posix.cpp index e0004c5730..0640b57305 100644 --- a/drivers/unix/mutex_posix.cpp +++ b/drivers/unix/mutex_posix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/unix/mutex_posix.h b/drivers/unix/mutex_posix.h index 80d85eee61..ee01ee629d 100644 --- a/drivers/unix/mutex_posix.h +++ b/drivers/unix/mutex_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 6e0bf97711..6a57a2e562 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -42,12 +42,8 @@ #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> @@ -59,8 +55,12 @@ #include <netinet/tcp.h> -#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) -#define MSG_NOSIGNAL SO_NOSIGPIPE +// BSD calls this flag IPV6_JOIN_GROUP +#if !defined(IPV6_ADD_MEMBERSHIP) && defined(IPV6_JOIN_GROUP) +#define IPV6_ADD_MEMBERSHIP IPV6_JOIN_GROUP +#endif +#if !defined(IPV6_DROP_MEMBERSHIP) && defined(IPV6_LEAVE_GROUP) +#define IPV6_DROP_MEMBERSHIP IPV6_LEAVE_GROUP #endif // Some custom defines to minimize ifdefs @@ -83,10 +83,6 @@ #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) @@ -94,7 +90,7 @@ #endif -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) { +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 @@ -114,7 +110,7 @@ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Addres } else { // IPv4 socket // IPv4 socket with IPv6 address - ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0); + ERR_FAIL_COND_V(!p_ip.is_wildcard() && !p_ip.is_ipv4(), 0); struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; addr4->sin_family = AF_INET; @@ -126,12 +122,11 @@ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Addres addr4->sin_addr.s_addr = INADDR_ANY; } - copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); return sizeof(sockaddr_in); } } -static void _set_ip_port(IP_Address &r_ip, uint16_t &r_port, struct sockaddr_storage *p_addr) { +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) { @@ -172,16 +167,23 @@ void NetSocketPosix::cleanup() { #endif } -NetSocketPosix::NetSocketPosix() { - _sock = SOCK_EMPTY; - _ip_type = IP::TYPE_NONE; - _is_stream = false; +NetSocketPosix::NetSocketPosix() : + _sock(SOCK_EMPTY), + _ip_type(IP::TYPE_NONE), + _is_stream(false) { } NetSocketPosix::~NetSocketPosix() { close(); } +// Silent a warning reported in #27594 + +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wlogical-op" +#endif + NetSocketPosix::NetError NetSocketPosix::_get_socket_error() { #if defined(WINDOWS_ENABLED) int err = WSAGetLastError(); @@ -206,7 +208,11 @@ NetSocketPosix::NetError NetSocketPosix::_get_socket_error() { #endif } -bool NetSocketPosix::_can_use_ip(const IP_Address p_ip, const bool p_for_bind) const { +#if defined(__GNUC__) && !defined(__clang__) +#pragma GCC diagnostic pop +#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; @@ -215,10 +221,59 @@ bool NetSocketPosix::_can_use_ip(const IP_Address p_ip, const bool p_for_bind) c } // 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 !(_ip_type != IP::TYPE_ANY && !p_ip.is_wildcard() && _ip_type != type); +} + +_FORCE_INLINE_ Error NetSocketPosix::_change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add) { + + ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); + ERR_FAIL_COND_V(!_can_use_ip(p_ip, false), ERR_INVALID_PARAMETER); + + // Need to force level and af_family to IP(v4) when using dual stacking and provided multicast group is IPv4 + IP::Type type = _ip_type == IP::TYPE_ANY && p_ip.is_ipv4() ? IP::TYPE_IPV4 : _ip_type; + // This needs to be the proper level for the multicast group, no matter if the socket is dual stacking. + int level = type == IP::TYPE_IPV4 ? IPPROTO_IP : IPPROTO_IPV6; + int ret = -1; + + IP_Address if_ip; + uint32_t if_v6id = 0; + Map<String, IP::Interface_Info> if_info; + IP::get_singleton()->get_local_interfaces(&if_info); + for (Map<String, IP::Interface_Info>::Element *E = if_info.front(); E; E = E->next()) { + IP::Interface_Info &c = E->get(); + if (c.name != p_if_name) + continue; + + if_v6id = (uint32_t)c.index.to_int64(); + if (type == IP::TYPE_IPV6) + break; // IPv6 uses index. + + for (List<IP_Address>::Element *F = c.ip_addresses.front(); F; F = F->next()) { + if (!F->get().is_ipv4()) + continue; // Wrong IP type + if_ip = F->get(); + break; + } + break; + } + + if (level == IPPROTO_IP) { + ERR_FAIL_COND_V(!if_ip.is_valid(), ERR_INVALID_PARAMETER); + struct ip_mreq greq; + int sock_opt = p_add ? IP_ADD_MEMBERSHIP : IP_DROP_MEMBERSHIP; + copymem(&greq.imr_multiaddr, p_ip.get_ipv4(), 4); + copymem(&greq.imr_interface, if_ip.get_ipv4(), 4); + ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq)); + } else { + struct ipv6_mreq greq; + int sock_opt = p_add ? IPV6_ADD_MEMBERSHIP : IPV6_DROP_MEMBERSHIP; + copymem(&greq.ipv6mr_multiaddr, p_ip.get_ipv6(), 16); + greq.ipv6mr_interface = if_v6id; + ret = setsockopt(_sock, level, sock_opt, (const char *)&greq, sizeof(greq)); } - return true; + ERR_FAIL_COND_V(ret != 0, FAILED); + + return OK; } void NetSocketPosix::_set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream) { @@ -279,6 +334,13 @@ Error NetSocketPosix::open(Type p_sock_type, IP::Type &ip_type) { } } #endif +#if defined(SO_NOSIGPIPE) + // Disable SIGPIPE (should only be relevant to stream sockets, but seems to affect UDP too on iOS) + int par = 1; + if (setsockopt(_sock, SOL_SOCKET, SO_NOSIGPIPE, SOCK_CBUF(&par), sizeof(int)) != 0) { + print_verbose("Unable to turn off SIGPIPE on socket"); + } +#endif return OK; } @@ -300,7 +362,7 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) { 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) { + if (::bind(_sock, (struct sockaddr *)&addr, addr_size) != 0) { close(); ERR_FAIL_V(ERR_UNAVAILABLE); } @@ -311,7 +373,7 @@ Error NetSocketPosix::bind(IP_Address p_addr, uint16_t p_port) { Error NetSocketPosix::listen(int p_max_pending) { ERR_FAIL_COND_V(!is_open(), ERR_UNCONFIGURED); - if (::listen(_sock, p_max_pending) == SOCK_EMPTY) { + if (::listen(_sock, p_max_pending) != 0) { close(); ERR_FAIL_V(FAILED); @@ -328,7 +390,7 @@ Error NetSocketPosix::connect_to_host(IP_Address p_host, uint16_t p_port) { 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) { + if (::connect(_sock, (struct sockaddr *)&addr, addr_size) != 0) { NetError err = _get_socket_error(); @@ -415,7 +477,7 @@ Error NetSocketPosix::poll(PollType p_type, int p_timeout) const { pfd.events = POLLOUT; break; case POLL_TYPE_IN_OUT: - pfd.events = POLLOUT || POLLIN; + pfd.events = POLLOUT | POLLIN; } int ret = ::poll(&pfd, 1, p_timeout); @@ -483,8 +545,10 @@ 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; +#ifdef MSG_NOSIGNAL if (_is_stream) flags = MSG_NOSIGNAL; +#endif r_sent = ::send(_sock, SOCK_CBUF(p_buffer), p_len, flags); if (r_sent < 0) { @@ -548,7 +612,7 @@ void NetSocketPosix::set_blocking_enabled(bool p_enabled) { void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) { ERR_FAIL_COND(!is_open()); - // This option is only avaiable in IPv6 sockets. + // This option is only available in IPv6 sockets. ERR_FAIL_COND(_ip_type == IP::TYPE_IPV4); int par = p_enabled ? 1 : 0; @@ -559,7 +623,7 @@ void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) { void NetSocketPosix::set_tcp_no_delay_enabled(bool p_enabled) { ERR_FAIL_COND(!is_open()); - ERR_FAIL_COND(_ip_type != TYPE_TCP); + 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) { @@ -612,10 +676,18 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { SOCKET_TYPE fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size); ERR_FAIL_COND_V(fd == SOCK_EMPTY, out); - _set_ip_port(r_ip, r_port, &their_addr); + _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); } + +Error NetSocketPosix::join_multicast_group(const IP_Address &p_multi_address, String p_if_name) { + return _change_multicast_group(p_multi_address, p_if_name, true); +} + +Error NetSocketPosix::leave_multicast_group(const IP_Address &p_multi_address, String p_if_name) { + return _change_multicast_group(p_multi_address, p_if_name, false); +} diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index 8177e01987..40406b241a 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -39,6 +39,7 @@ #define SOCKET_TYPE SOCKET #else +#include <sys/socket.h> #define SOCKET_TYPE int #endif @@ -59,21 +60,24 @@ private: NetError _get_socket_error(); void _set_socket(SOCKET_TYPE p_sock, IP::Type p_ip_type, bool p_is_stream); + _FORCE_INLINE_ Error _change_multicast_group(IP_Address p_ip, String p_if_name, bool p_add); protected: static NetSocket *_create_func(); - bool _can_use_ip(const IP_Address p_ip, const bool p_for_bind) const; + bool _can_use_ip(const IP_Address &p_ip, const bool p_for_bind) const; public: 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 connect_to_host(IP_Address p_host, 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); @@ -90,6 +94,8 @@ public: 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); + virtual Error join_multicast_group(const IP_Address &p_multi_address, String p_if_name); + virtual Error leave_multicast_group(const IP_Address &p_multi_address, String p_if_name); NetSocketPosix(); ~NetSocketPosix(); diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 9936c95cf9..b3d98a0648 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -45,6 +45,7 @@ #ifdef __APPLE__ #include <mach-o/dyld.h> +#include <mach/mach_time.h> #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) @@ -64,6 +65,30 @@ #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_FAIL_COND_MSG(ret != 0, "OS CLOCK IS NOT WORKING!"); + _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_FAIL_COND_MSG(clock_gettime(GODOT_CLOCK, &tv_now) != 0, "OS CLOCK IS NOT WORKING!"); + _clock_start = ((uint64_t)tv_now.tv_nsec / 1000L) + (uint64_t)tv_now.tv_sec * 1000000L; +} +#endif + void OS_Unix::debug_break() { assert(false); @@ -81,6 +106,7 @@ void OS_Unix::initialize_debugging() { if (ScriptDebugger::get_singleton() != NULL) { struct sigaction action; + memset(&action, 0, sizeof(action)); action.sa_handler = handle_interrupt; sigaction(SIGINT, &action, NULL); } @@ -91,15 +117,6 @@ int OS_Unix::unix_initialize_audio(int p_audio_driver) { return 0; } -// Very simple signal handler to reap processes where ::execute was called with -// !p_blocking -void handle_sigchld(int sig) { - int saved_errno = errno; - while (waitpid((pid_t)(-1), 0, WNOHANG) > 0) { - } - errno = saved_errno; -} - void OS_Unix::initialize_core() { #ifdef NO_THREADS @@ -126,16 +143,7 @@ void OS_Unix::initialize_core() { IP_Unix::make_default(); #endif - ticks_start = 0; - ticks_start = get_ticks_usec(); - - struct sigaction sa; - sa.sa_handler = &handle_sigchld; - sigemptyset(&sa.sa_mask); - sa.sa_flags = SA_RESTART | SA_NOCLDSTOP; - if (sigaction(SIGCHLD, &sa, 0) == -1) { - perror("ERROR sigaction() failed:"); - } + _setup_clock(); } void OS_Unix::finalize_core() { @@ -160,7 +168,7 @@ String OS_Unix::get_stdin_string(bool p_block) { return ""; } -String OS_Unix::get_name() { +String OS_Unix::get_name() const { return "Unix"; } @@ -176,6 +184,12 @@ uint64_t OS_Unix::get_system_time_secs() const { return uint64_t(tv_now.tv_sec); } +uint64_t OS_Unix::get_system_time_msecs() const { + struct timeval tv_now; + gettimeofday(&tv_now, NULL); + return uint64_t(tv_now.tv_sec) * 1000 + uint64_t(tv_now.tv_usec) / 1000; +} + OS::Date OS_Unix::get_date(bool utc) const { time_t t = time(NULL); @@ -240,23 +254,33 @@ OS::TimeZoneInfo OS_Unix::get_time_zone_info() const { void OS_Unix::delay_usec(uint32_t p_usec) const { - struct timespec rem = { static_cast<time_t>(p_usec / 1000000), static_cast<long>((p_usec % 1000000) * 1000) }; + struct timespec rem = { static_cast<time_t>(p_usec / 1000000), (static_cast<long>(p_usec) % 1000000) * 1000 }; while (nanosleep(&rem, &rem) == EINTR) { } } 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() succeeded, 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) { +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, Mutex *p_pipe_mutex) { +#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; @@ -274,17 +298,23 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo } FILE *f = popen(argss.utf8().get_data(), "r"); - ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot pipe stream from process running with following arguments '" + argss + "'."); char buf[65535]; + while (fgets(buf, 65535, f)) { + if (p_pipe_mutex) { + p_pipe_mutex->lock(); + } (*r_pipe) += buf; + if (p_pipe_mutex) { + p_pipe_mutex->unlock(); + } } - int rv = pclose(f); if (r_exitcode) - *r_exitcode = rv; + *r_exitcode = WEXITSTATUS(rv); return OK; } @@ -294,6 +324,13 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo if (pid == 0) { // is child + + if (!p_blocking) { + // For non blocking calls, create a new session-ID so parent won't wait for it. + // This ensures the process won't go zombie at end. + setsid(); + } + Vector<CharString> cs; cs.push_back(p_path.utf8()); for (int i = 0; i < p_arguments.size(); i++) @@ -316,6 +353,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo waitpid(pid, &status, 0); if (r_exitcode) *r_exitcode = WEXITSTATUS(status); + } else { if (r_child_id) @@ -323,6 +361,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) { @@ -379,10 +418,7 @@ Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle } p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW); - if (!p_library_handle) { - ERR_EXPLAIN("Can't open dynamic library: " + p_path + ". Error: " + dlerror()); - ERR_FAIL_V(ERR_CANT_OPEN); - } + ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, "Can't open dynamic library: " + p_path + ". Error: " + dlerror()); return OK; } @@ -401,12 +437,9 @@ Error OS_Unix::get_dynamic_library_symbol_handle(void *p_library_handle, const S error = dlerror(); if (error != NULL) { - if (!p_optional) { - ERR_EXPLAIN("Can't resolve symbol " + p_name + ". Error: " + error); - ERR_FAIL_V(ERR_CANT_RESOLVE); - } else { - return ERR_CANT_RESOLVE; - } + ERR_FAIL_COND_V_MSG(!p_optional, ERR_CANT_RESOLVE, "Can't resolve symbol " + p_name + ". Error: " + error + "."); + + return ERR_CANT_RESOLVE; } return OK; } @@ -426,6 +459,11 @@ String OS_Unix::get_environment(const String &p_var) const { return ""; } +bool OS_Unix::set_environment(const String &p_var, const String &p_value) const { + + return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0; +} + int OS_Unix::get_processor_count() const { return sysconf(_SC_NPROCESSORS_CONF); @@ -456,9 +494,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 f4abfa2dd4..a263147e23 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -31,10 +31,6 @@ #ifndef OS_UNIX_H #define OS_UNIX_H -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - #ifdef UNIX_ENABLED #include "core/os/os.h" @@ -42,8 +38,6 @@ 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 @@ -78,7 +72,7 @@ public: virtual Error set_cwd(const String &p_cwd); - virtual String get_name(); + virtual String get_name() const; virtual Date get_date(bool utc) const; virtual Time get_time(bool utc) const; @@ -86,16 +80,18 @@ public: virtual uint64_t get_unix_time() const; virtual uint64_t get_system_time_secs() const; + virtual uint64_t get_system_time_msecs() const; virtual void delay_usec(uint32_t p_usec) const; virtual uint64_t get_ticks_usec() const; - virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false); + virtual Error execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id = NULL, String *r_pipe = NULL, int *r_exitcode = NULL, bool read_stderr = false, Mutex *p_pipe_mutex = NULL); virtual Error kill(const ProcessID &p_pid); virtual int get_process_id() const; virtual bool has_environment(const String &p_var) const; virtual String get_environment(const String &p_var) const; + virtual bool set_environment(const String &p_var, const String &p_value) const; virtual String get_locale() const; virtual int get_processor_count() const; diff --git a/drivers/unix/rw_lock_posix.cpp b/drivers/unix/rw_lock_posix.cpp index 27b19c30d5..c146061704 100644 --- a/drivers/unix/rw_lock_posix.cpp +++ b/drivers/unix/rw_lock_posix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/unix/rw_lock_posix.h b/drivers/unix/rw_lock_posix.h index 897b617f98..7cbe5c992f 100644 --- a/drivers/unix/rw_lock_posix.h +++ b/drivers/unix/rw_lock_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/unix/semaphore_posix.cpp b/drivers/unix/semaphore_posix.cpp index 26c2aeab28..5aa51d77d1 100644 --- a/drivers/unix/semaphore_posix.cpp +++ b/drivers/unix/semaphore_posix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/unix/semaphore_posix.h b/drivers/unix/semaphore_posix.h index 025b87c0d7..83e75c9a82 100644 --- a/drivers/unix/semaphore_posix.h +++ b/drivers/unix/semaphore_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -36,9 +36,7 @@ #if defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED) #include <semaphore.h> -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ + class SemaphorePosix : public Semaphore { mutable sem_t sem; 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/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp index c7b4daf4ad..6e3a3c5f9a 100644 --- a/drivers/unix/syslog_logger.cpp +++ b/drivers/unix/syslog_logger.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h index 745264ab6f..49a34dacc3 100644 --- a/drivers/unix/syslog_logger.h +++ b/drivers/unix/syslog_logger.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -37,7 +37,7 @@ class SyslogLogger : public Logger { public: - virtual void logv(const char *p_format, va_list p_list, bool p_err); + virtual void logv(const char *p_format, va_list p_list, bool p_err) _PRINTF_FORMAT_ATTRIBUTE_2_0; virtual void print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type); virtual ~SyslogLogger(); diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp index fcefe0a3b3..ef3f5fb49c 100644 --- a/drivers/unix/thread_posix.cpp +++ b/drivers/unix/thread_posix.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -40,9 +40,13 @@ #include "core/os/memory.h" #include "core/safe_refcount.h" +static void _thread_id_key_destr_callback(void *p_value) { + memdelete(static_cast<Thread::ID *>(p_value)); +} + static pthread_key_t _create_thread_id_key() { pthread_key_t key; - pthread_key_create(&key, NULL); + pthread_key_create(&key, &_thread_id_key_destr_callback); return key; } @@ -63,7 +67,7 @@ void *ThreadPosix::thread_callback(void *userdata) { ThreadPosix *t = reinterpret_cast<ThreadPosix *>(userdata); t->id = atomic_increment(&next_thread_id); - pthread_setspecific(thread_id_key, (void *)t->id); + pthread_setspecific(thread_id_key, (void *)memnew(ID(t->id))); ScriptServer::thread_enter(); //scripts may need to attach a stack @@ -89,7 +93,14 @@ Thread *ThreadPosix::create_func_posix(ThreadCreateCallback p_callback, void *p_ } Thread::ID ThreadPosix::get_thread_id_func_posix() { - return (ID)pthread_getspecific(thread_id_key); + void *value = pthread_getspecific(thread_id_key); + + if (value) + return *static_cast<ID *>(value); + + ID new_id = atomic_increment(&next_thread_id); + pthread_setspecific(thread_id_key, (void *)memnew(ID(new_id))); + return new_id; } void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { @@ -103,8 +114,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 +126,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 20d103232e..5edacd3a0c 100644 --- a/drivers/unix/thread_posix.h +++ b/drivers/unix/thread_posix.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -31,10 +31,6 @@ #ifndef THREAD_POSIX_H #define THREAD_POSIX_H -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - #if (defined(UNIX_ENABLED) || defined(PTHREAD_ENABLED)) && !defined(NO_THREADS) #include "core/os/thread.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 3d4979175b..adc3cc8d65 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -167,13 +167,13 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); for (ULONG i = 0; i < count && !found; i++) { - IMMDevice *device = NULL; + IMMDevice *tmp_device = NULL; - hr = devices->Item(i, &device); + hr = devices->Item(i, &tmp_device); ERR_BREAK(hr != S_OK); IPropertyStore *props = NULL; - hr = device->OpenPropertyStore(STGM_READ, &props); + hr = tmp_device->OpenPropertyStore(STGM_READ, &props); ERR_BREAK(hr != S_OK); PROPVARIANT propvar; @@ -183,7 +183,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c ERR_BREAK(hr != S_OK); if (p_device->device_name == String(propvar.pwszVal)) { - hr = device->GetId(&strId); + hr = tmp_device->GetId(&strId); ERR_BREAK(hr != S_OK); found = true; @@ -191,7 +191,7 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c PropVariantClear(&propvar); props->Release(); - device->Release(); + tmp_device->Release(); } if (found) { @@ -238,6 +238,32 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c hr = p_device->audio_client->GetMixFormat(&pwfex); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + print_verbose("WASAPI: wFormatTag = " + itos(pwfex->wFormatTag)); + print_verbose("WASAPI: nChannels = " + itos(pwfex->nChannels)); + print_verbose("WASAPI: nSamplesPerSec = " + itos(pwfex->nSamplesPerSec)); + print_verbose("WASAPI: nAvgBytesPerSec = " + itos(pwfex->nAvgBytesPerSec)); + print_verbose("WASAPI: nBlockAlign = " + itos(pwfex->nBlockAlign)); + print_verbose("WASAPI: wBitsPerSample = " + itos(pwfex->wBitsPerSample)); + print_verbose("WASAPI: cbSize = " + itos(pwfex->cbSize)); + + WAVEFORMATEX *closest = NULL; + hr = p_device->audio_client->IsFormatSupported(AUDCLNT_SHAREMODE_SHARED, pwfex, &closest); + if (hr == S_FALSE) { + WARN_PRINT("WASAPI: Mix format is not supported by the Device"); + if (closest) { + print_verbose("WASAPI: closest->wFormatTag = " + itos(closest->wFormatTag)); + print_verbose("WASAPI: closest->nChannels = " + itos(closest->nChannels)); + print_verbose("WASAPI: closest->nSamplesPerSec = " + itos(closest->nSamplesPerSec)); + print_verbose("WASAPI: closest->nAvgBytesPerSec = " + itos(closest->nAvgBytesPerSec)); + print_verbose("WASAPI: closest->nBlockAlign = " + itos(closest->nBlockAlign)); + print_verbose("WASAPI: closest->wBitsPerSample = " + itos(closest->wBitsPerSample)); + print_verbose("WASAPI: closest->cbSize = " + itos(closest->cbSize)); + + WARN_PRINT("WASAPI: Using closest match instead"); + pwfex = closest; + } + } + // Since we're using WASAPI Shared Mode we can't control any of these, we just tag along p_device->channels = pwfex->nChannels; p_device->format_tag = pwfex->wFormatTag; @@ -263,14 +289,14 @@ Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_c } DWORD streamflags = 0; - if (mix_rate != pwfex->nSamplesPerSec) { + if ((DWORD)mix_rate != pwfex->nSamplesPerSec) { streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST; pwfex->nSamplesPerSec = mix_rate; pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8); } hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, NULL); - ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_CANT_OPEN, "WASAPI: Initialize failed with error 0x" + String::num_uint64(hr, 16) + "."); if (p_capture) { hr = p_device->audio_client->GetService(IID_IAudioCaptureClient, (void **)&p_device->capture_client); @@ -316,8 +342,8 @@ Error AudioDriverWASAPI::init_render_device(bool reinit) { // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) samples_in.resize(buffer_frames * channels); - input_position = 0; - input_size = 0; + capture_position = 0; + capture_size = 0; print_verbose("WASAPI: detected " + itos(channels) + " channels"); print_verbose("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); @@ -336,10 +362,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; + capture_buffer_init(max_frames); return OK; } @@ -547,7 +570,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { if (ad->audio_output.active) { ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw()); } else { - for (unsigned int i = 0; i < ad->samples_in.size(); i++) { + for (int i = 0; i < ad->samples_in.size(); i++) { ad->samples_in.write[i] = 0; } } @@ -675,7 +698,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { ERR_BREAK(hr != S_OK); // fixme: Only works for floating point atm - for (int j = 0; j < num_frames_available; j++) { + for (UINT32 j = 0; j < num_frames_available; j++) { int32_t l, r; if (flags & AUDCLNT_BUFFERFLAGS_SILENT) { @@ -692,8 +715,8 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { } } - ad->input_buffer_write(l); - ad->input_buffer_write(r); + ad->capture_buffer_write(l); + ad->capture_buffer_write(r); } read_frames += num_frames_available; @@ -796,19 +819,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/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index 3d94f3ba49..05a2c6faef 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -58,17 +58,17 @@ class AudioDriverWASAPI : public AudioDriver { String device_name; String new_device; - AudioDeviceWASAPI() { - audio_client = NULL; - render_client = NULL; - capture_client = NULL; - active = false; - format_tag = 0; - bits_per_sample = 0; - channels = 0; - frame_size = 0; - device_name = "Default"; - new_device = "Default"; + AudioDeviceWASAPI() : + audio_client(NULL), + render_client(NULL), + capture_client(NULL), + active(false), + format_tag(0), + bits_per_sample(0), + channels(0), + frame_size(0), + device_name("Default"), + new_device("Default") { } }; 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 589e9e0870..9eac15f774 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -346,6 +346,34 @@ size_t DirAccessWindows::get_space_left() { return (size_t)bytes; } +String DirAccessWindows::get_filesystem_type() const { + String path = fix_path(const_cast<DirAccessWindows *>(this)->get_current_dir()); + + int unit_end = path.find(":"); + ERR_FAIL_COND_V(unit_end == -1, String()); + String unit = path.substr(0, unit_end + 1) + "\\"; + + WCHAR szVolumeName[100]; + WCHAR szFileSystemName[10]; + DWORD dwSerialNumber = 0; + DWORD dwMaxFileNameLength = 0; + DWORD dwFileSystemFlags = 0; + + if (::GetVolumeInformationW(unit.c_str(), + szVolumeName, + sizeof(szVolumeName), + &dwSerialNumber, + &dwMaxFileNameLength, + &dwFileSystemFlags, + szFileSystemName, + sizeof(szFileSystemName)) == TRUE) { + + return String(szFileSystemName); + } + + ERR_FAIL_V(""); +} + DirAccessWindows::DirAccessWindows() { p = memnew(DirAccessWindowsPrivate); @@ -366,7 +394,7 @@ DirAccessWindows::DirAccessWindows() { if (mask & (1 << i)) { //DRIVE EXISTS - drives[drive_count] = 'a' + i; + drives[drive_count] = 'A' + i; drive_count++; } } diff --git a/drivers/windows/dir_access_windows.h b/drivers/windows/dir_access_windows.h index 9f5d0b6d93..10eee07f0c 100644 --- a/drivers/windows/dir_access_windows.h +++ b/drivers/windows/dir_access_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -82,6 +82,8 @@ public: //virtual FileType get_file_type() const; size_t get_space_left(); + virtual String get_filesystem_type() const; + DirAccessWindows(); ~DirAccessWindows(); }; diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index b4492a2022..fb21c0c5a1 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -38,6 +38,7 @@ #include <shlwapi.h> #include <windows.h> +#include <errno.h> #include <sys/stat.h> #include <sys/types.h> #include <tchar.h> @@ -93,7 +94,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { // a file using the wrong case (which *works* on Windows, but won't on other // platforms). if (p_mode_flags == READ) { - WIN32_FIND_DATAW d = { 0 }; + WIN32_FIND_DATAW d; HANDLE f = FindFirstFileW(path.c_str(), &d); if (f) { String fname = d.cFileName; @@ -114,17 +115,25 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { path = path + ".tmp"; } - f = _wfopen(path.c_str(), mode_string); + errno_t errcode = _wfopen_s(&f, path.c_str(), mode_string); if (f == NULL) { - last_error = ERR_FILE_CANT_OPEN; - return ERR_FILE_CANT_OPEN; + switch (errcode) { + case ENOENT: { + last_error = ERR_FILE_NOT_FOUND; + } break; + default: { + last_error = ERR_FILE_CANT_OPEN; + } break; + } + return last_error; } else { last_error = OK; flags = p_mode_flags; return OK; } } + void FileAccessWindows::close() { if (!f) @@ -167,13 +176,11 @@ void FileAccessWindows::close() { if (close_fail_notify) { close_fail_notify(save_path); } - - ERR_EXPLAIN("Safe save failed. This may be a permissions problem, but also may happen because you are running a paranoid antivirus. If this is the case, please switch to Windows Defender or disable the 'safe save' option in editor settings. This makes it work, but increases the risk of file corruption in a crash."); } save_path = ""; - ERR_FAIL_COND(rename_error); + ERR_FAIL_COND_MSG(rename_error, "Safe save failed. This may be a permissions problem, but also may happen because you are running a paranoid antivirus. If this is the case, please switch to Windows Defender or disable the 'safe save' option in editor settings. This makes it work, but increases the risk of file corruption in a crash."); } } @@ -197,12 +204,14 @@ void FileAccessWindows::seek(size_t p_position) { last_error = OK; if (fseek(f, p_position, SEEK_SET)) check_errors(); + prev_op = 0; } void FileAccessWindows::seek_end(int64_t p_position) { ERR_FAIL_COND(!f); if (fseek(f, p_position, SEEK_END)) check_errors(); + prev_op = 0; } size_t FileAccessWindows::get_position() const { @@ -234,6 +243,12 @@ bool FileAccessWindows::eof_reached() const { uint8_t FileAccessWindows::get_8() const { ERR_FAIL_COND_V(!f, 0); + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == WRITE) { + fflush(f); + } + prev_op = READ; + } uint8_t b; if (fread(&b, 1, 1, f) == 0) { check_errors(); @@ -246,6 +261,12 @@ uint8_t FileAccessWindows::get_8() const { int FileAccessWindows::get_buffer(uint8_t *p_dst, int p_length) const { ERR_FAIL_COND_V(!f, -1); + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == WRITE) { + fflush(f); + } + prev_op = READ; + } int read = fread(p_dst, 1, p_length, f); check_errors(); return read; @@ -260,17 +281,35 @@ void FileAccessWindows::flush() { ERR_FAIL_COND(!f); fflush(f); + if (prev_op == WRITE) + prev_op = 0; } void FileAccessWindows::store_8(uint8_t p_dest) { ERR_FAIL_COND(!f); + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == READ) { + if (last_error != ERR_FILE_EOF) { + fseek(f, 0, SEEK_CUR); + } + } + prev_op = WRITE; + } fwrite(&p_dest, 1, 1, f); } void FileAccessWindows::store_buffer(const uint8_t *p_src, int p_length) { ERR_FAIL_COND(!f); - ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length); + if (flags == READ_WRITE || flags == WRITE_READ) { + if (prev_op == READ) { + if (last_error != ERR_FILE_EOF) { + fseek(f, 0, SEEK_CUR); + } + } + prev_op = WRITE; + } + ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != (size_t)p_length); } bool FileAccessWindows::file_exists(const String &p_name) { @@ -278,7 +317,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; @@ -302,16 +341,23 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) { return st.st_mtime; } else { - ERR_EXPLAIN("Failed to get modified time for: " + file); - ERR_FAIL_V(0); + ERR_FAIL_V_MSG(0, "Failed to get modified time for: " + file + "."); } } -FileAccessWindows::FileAccessWindows() { +uint32_t FileAccessWindows::_get_unix_permissions(const String &p_file) { + return 0; +} - f = NULL; - flags = 0; - last_error = OK; +Error FileAccessWindows::_set_unix_permissions(const String &p_file, uint32_t p_permissions) { + return ERR_UNAVAILABLE; +} + +FileAccessWindows::FileAccessWindows() : + f(NULL), + flags(0), + prev_op(0), + last_error(OK) { } FileAccessWindows::~FileAccessWindows() { diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 6f985e68b4..e7f9fc690d 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -38,15 +38,12 @@ #include <stdio.h> -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class FileAccessWindows : public FileAccess { FILE *f; int flags; void check_errors() const; + mutable int prev_op; mutable Error last_error; String path; String path_src; @@ -79,6 +76,8 @@ public: virtual bool file_exists(const String &p_name); ///< return true if a file exists uint64_t _get_modified_time(const String &p_file); + virtual uint32_t _get_unix_permissions(const String &p_file); + virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions); FileAccessWindows(); virtual ~FileAccessWindows(); diff --git a/drivers/windows/mutex_windows.cpp b/drivers/windows/mutex_windows.cpp index 9fc6485be3..cfb72293aa 100644 --- a/drivers/windows/mutex_windows.cpp +++ b/drivers/windows/mutex_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/windows/mutex_windows.h b/drivers/windows/mutex_windows.h index 5c3a8eb331..582d26029c 100644 --- a/drivers/windows/mutex_windows.h +++ b/drivers/windows/mutex_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -37,10 +37,6 @@ #include <windows.h> -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class MutexWindows : public Mutex { #ifdef WINDOWS_USE_MUTEX diff --git a/drivers/windows/rw_lock_windows.cpp b/drivers/windows/rw_lock_windows.cpp index ef00141928..40e424c4af 100644 --- a/drivers/windows/rw_lock_windows.cpp +++ b/drivers/windows/rw_lock_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/windows/rw_lock_windows.h b/drivers/windows/rw_lock_windows.h index 742a0930d4..1e768728a0 100644 --- a/drivers/windows/rw_lock_windows.h +++ b/drivers/windows/rw_lock_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ diff --git a/drivers/windows/semaphore_windows.cpp b/drivers/windows/semaphore_windows.cpp index 34dd387705..55b47e45eb 100644 --- a/drivers/windows/semaphore_windows.cpp +++ b/drivers/windows/semaphore_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -54,7 +54,8 @@ int SemaphoreWindows::get() const { case WAIT_TIMEOUT: { return 0; } break; - default: {} + default: { + } } ERR_FAIL_V(-1); diff --git a/drivers/windows/semaphore_windows.h b/drivers/windows/semaphore_windows.h index 1e2f9c152e..cfd33d033a 100644 --- a/drivers/windows/semaphore_windows.h +++ b/drivers/windows/semaphore_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -37,10 +37,6 @@ #include <windows.h> -/** - @author Juan Linietsky <reduzio@gmail.com> -*/ - class SemaphoreWindows : public Semaphore { mutable HANDLE semaphore; diff --git a/drivers/windows/shell_windows.cpp b/drivers/windows/shell_windows.cpp deleted file mode 100644 index 20e996d776..0000000000 --- a/drivers/windows/shell_windows.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************/ -/* shell_windows.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 - -#ifdef UWP_ENABLED - -// Use Launcher class on windows 8 - -#else - -// -// C++ Implementation: shell_windows -// -// Description: -// -// -// Author: Juan Linietsky <reduzio@gmail.com>, (C) 2008 -// -// Copyright: See COPYING file that comes with this distribution -// -// -#include "shell_windows.h" - -#include <windows.h> - -void ShellWindows::execute(String p_path) { - - ShellExecuteW(NULL, L"open", p_path.c_str(), NULL, NULL, SW_SHOWNORMAL); -} - -ShellWindows::ShellWindows() { -} - -ShellWindows::~ShellWindows() { -} - -#endif - -#endif diff --git a/drivers/windows/shell_windows.h b/drivers/windows/shell_windows.h deleted file mode 100644 index 98972a9bb1..0000000000 --- a/drivers/windows/shell_windows.h +++ /dev/null @@ -1,52 +0,0 @@ -/*************************************************************************/ -/* shell_windows.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 SHELL_WINDOWS_H -#define SHELL_WINDOWS_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); - - ShellWindows(); - - ~ShellWindows(); -}; - -#endif -#endif diff --git a/drivers/windows/thread_windows.cpp b/drivers/windows/thread_windows.cpp index 52dcfacdf8..8a2992e0c2 100644 --- a/drivers/windows/thread_windows.cpp +++ b/drivers/windows/thread_windows.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -52,6 +52,7 @@ DWORD ThreadWindows::thread_callback(LPVOID userdata) { t->id = (ID)GetCurrentThreadId(); // must implement t->callback(t->user); + SetEvent(t->handle); ScriptServer::thread_exit(); @@ -63,13 +64,9 @@ Thread *ThreadWindows::create_func_windows(ThreadCreateCallback p_callback, void ThreadWindows *tr = memnew(ThreadWindows); tr->callback = p_callback; tr->user = p_user; - tr->handle = CreateThread( - NULL, // default security attributes - 0, // use default stack size - thread_callback, // thread function name - tr, // argument to thread function - 0, // use default creation flags - NULL); // returns the thread identifier + tr->handle = CreateEvent(NULL, TRUE, FALSE, NULL); + + QueueUserWorkItem(thread_callback, tr, WT_EXECUTELONGFUNCTION); return tr; } @@ -93,9 +90,8 @@ void ThreadWindows::make_default() { wait_to_finish_func = wait_to_finish_func_windows; } -ThreadWindows::ThreadWindows() { - - handle = NULL; +ThreadWindows::ThreadWindows() : + handle(NULL) { } ThreadWindows::~ThreadWindows() { diff --git a/drivers/windows/thread_windows.h b/drivers/windows/thread_windows.h index 5d2838e54f..b47452838c 100644 --- a/drivers/windows/thread_windows.h +++ b/drivers/windows/thread_windows.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -38,10 +38,6 @@ #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/midi_driver_winmidi.cpp index 1d4bf1a1e2..65676b629a 100644 --- a/drivers/winmidi/win_midi.cpp +++ b/drivers/winmidi/midi_driver_winmidi.cpp @@ -1,12 +1,12 @@ /*************************************************************************/ -/* win_midi.cpp */ +/* midi_driver_winmidi.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -30,7 +30,7 @@ #ifdef WINMIDI_ENABLED -#include "win_midi.h" +#include "midi_driver_winmidi.h" #include "core/print_string.h" @@ -104,4 +104,4 @@ MIDIDriverWinMidi::~MIDIDriverWinMidi() { close(); } -#endif +#endif // WINMIDI_ENABLED diff --git a/drivers/winmidi/win_midi.h b/drivers/winmidi/midi_driver_winmidi.h index 87a349d5d1..2eaa70ef8d 100644 --- a/drivers/winmidi/win_midi.h +++ b/drivers/winmidi/midi_driver_winmidi.h @@ -1,12 +1,12 @@ /*************************************************************************/ -/* win_midi.h */ +/* midi_driver_winmidi.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) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -30,8 +30,8 @@ #ifdef WINMIDI_ENABLED -#ifndef WIN_MIDI_H -#define WIN_MIDI_H +#ifndef MIDI_DRIVER_WINMIDI_H +#define MIDI_DRIVER_WINMIDI_H #include "core/os/midi_driver.h" #include "core/vector.h" @@ -57,5 +57,5 @@ public: virtual ~MIDIDriverWinMidi(); }; -#endif -#endif +#endif // MIDI_DRIVER_WINMIDI_H +#endif // WINMIDI_ENABLED diff --git a/drivers/xaudio2/SCsub b/drivers/xaudio2/SCsub index cb780a893b..de750525ab 100644 --- a/drivers/xaudio2/SCsub +++ b/drivers/xaudio2/SCsub @@ -3,7 +3,5 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") -env.Append(CXXFLAGS=['-DXAUDIO2_ENABLED']) +env.Append(CPPDEFINES=['XAUDIO2_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 452a1105ca..6d729c50ab 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.cpp +++ b/drivers/xaudio2/audio_driver_xaudio2.cpp @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ @@ -45,12 +45,12 @@ Error AudioDriverXAudio2::init() { pcm_open = false; samples_in = NULL; - mix_rate = 48000; + mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); // FIXME: speaker_mode seems unused in the Xaudio2 driver so far speaker_mode = SPEAKER_MODE_STEREO; channels = 2; - int latency = GLOBAL_DEF_RST("audio/output_latency", 25); + int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); buffer_size = closest_power_of_2(latency * mix_rate / 1000); samples_in = memnew_arr(int32_t, buffer_size * channels); @@ -63,15 +63,10 @@ Error AudioDriverXAudio2::init() { HRESULT hr; hr = XAudio2Create(&xaudio, 0, XAUDIO2_DEFAULT_PROCESSOR); - if (hr != S_OK) { - ERR_EXPLAIN("Error creating XAudio2 engine."); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 engine."); + hr = xaudio->CreateMasteringVoice(&mastering_voice); - if (hr != S_OK) { - ERR_EXPLAIN("Error creating XAudio2 mastering voice."); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 mastering voice."); wave_format.nChannels = channels; wave_format.cbSize = 0; @@ -82,16 +77,13 @@ Error AudioDriverXAudio2::init() { wave_format.nAvgBytesPerSec = mix_rate * wave_format.nBlockAlign; hr = xaudio->CreateSourceVoice(&source_voice, &wave_format, 0, XAUDIO2_MAX_FREQ_RATIO, &voice_callback); - if (hr != S_OK) { - ERR_EXPLAIN("Error creating XAudio2 source voice. " + itos(hr)); - ERR_FAIL_V(ERR_UNAVAILABLE); - } + ERR_FAIL_COND_V_MSG(hr != S_OK, ERR_UNAVAILABLE, "Error creating XAudio2 source voice. Error code: " + itos(hr) + "."); mutex = Mutex::create(); thread = Thread::create(AudioDriverXAudio2::thread_func, this); return OK; -}; +} void AudioDriverXAudio2::thread_func(void *p_udata) { @@ -131,30 +123,27 @@ void AudioDriverXAudio2::thread_func(void *p_udata) { WaitForSingleObject(ad->voice_callback.buffer_end_event, INFINITE); } } - }; + } ad->thread_exited = true; -}; +} void AudioDriverXAudio2::start() { active = true; HRESULT hr = source_voice->Start(0); - if (hr != S_OK) { - ERR_EXPLAIN("XAudio2 start error " + itos(hr)); - ERR_FAIL(); - } -}; + ERR_FAIL_COND_MSG(hr != S_OK, "Error starting XAudio2 driver. Error code: " + itos(hr) + "."); +} int AudioDriverXAudio2::get_mix_rate() const { return mix_rate; -}; +} AudioDriver::SpeakerMode AudioDriverXAudio2::get_speaker_mode() const { return speaker_mode; -}; +} float AudioDriverXAudio2::get_latency() { @@ -172,13 +161,13 @@ void AudioDriverXAudio2::lock() { if (!thread || !mutex) return; mutex->lock(); -}; +} void AudioDriverXAudio2::unlock() { if (!thread || !mutex) return; mutex->unlock(); -}; +} void AudioDriverXAudio2::finish() { @@ -195,12 +184,12 @@ void AudioDriverXAudio2::finish() { if (samples_in) { memdelete_arr(samples_in); - }; + } if (samples_out[0]) { for (int i = 0; i < AUDIO_BUFFERS; i++) { memdelete_arr(samples_out[i]); } - }; + } mastering_voice->DestroyVoice(); @@ -208,20 +197,18 @@ void AudioDriverXAudio2::finish() { if (mutex) memdelete(mutex); thread = NULL; -}; - -AudioDriverXAudio2::AudioDriverXAudio2() { +} - mutex = NULL; - thread = NULL; +AudioDriverXAudio2::AudioDriverXAudio2() : + thread(NULL), + mutex(NULL), + current_buffer(0) { wave_format = { 0 }; for (int i = 0; i < AUDIO_BUFFERS; i++) { xaudio_buffer[i] = { 0 }; samples_out[i] = 0; } - current_buffer = 0; -}; - -AudioDriverXAudio2::~AudioDriverXAudio2(){ +} -}; +AudioDriverXAudio2::~AudioDriverXAudio2() { +} diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h index 0867c56128..f2fdf63cde 100644 --- a/drivers/xaudio2/audio_driver_xaudio2.h +++ b/drivers/xaudio2/audio_driver_xaudio2.h @@ -5,8 +5,8 @@ /* GODOT ENGINE */ /* https://godotengine.org */ /*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ +/* Copyright (c) 2007-2019 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2019 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 */ 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]) |