diff options
Diffstat (limited to 'drivers')
44 files changed, 1831 insertions, 610 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index b8bba91378..34d6254578 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -4,7 +4,7 @@ Import('env') env.drivers_sources = [] -if ("builtin_zlib" in env and env["builtin_zlib"] == "yes"): +if 'builtin_zlib' in env and env['builtin_zlib']: SConscript("zlib/SCsub") # OS drivers @@ -13,11 +13,12 @@ SConscript('windows/SCsub') # Sounds drivers SConscript('alsa/SCsub') +SConscript('coreaudio/SCsub') SConscript('pulseaudio/SCsub') if (env["platform"] == "windows"): SConscript("rtaudio/SCsub") SConscript("wasapi/SCsub") -if (env["xaudio2"] == "yes"): +if env['xaudio2']: SConscript("xaudio2/SCsub") # Graphics drivers @@ -29,10 +30,10 @@ SConscript("png/SCsub") # Tools override # FIXME: Should likely be integrated in the tools/ codebase -if (env["tools"] == "yes"): +if env['tools']: SConscript("convex_decomp/SCsub") -if env['vsproj'] == "yes": +if env['vsproj']: env.AddToVSProject(env.drivers_sources) if env.split_drivers: diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp index 40c66b0bc5..216100bac6 100644 --- a/drivers/alsa/audio_driver_alsa.cpp +++ b/drivers/alsa/audio_driver_alsa.cpp @@ -31,6 +31,7 @@ #ifdef ALSA_ENABLED +#include "os/os.h" #include "project_settings.h" #include <errno.h> @@ -44,7 +45,7 @@ Error AudioDriverALSA::init() { samples_in = NULL; samples_out = NULL; - mix_rate = GLOBAL_DEF("audio/mix_rate", 44100); + mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE); speaker_mode = SPEAKER_MODE_STEREO; channels = 2; @@ -86,19 +87,25 @@ Error AudioDriverALSA::init() { status = snd_pcm_hw_params_set_rate_near(pcm_handle, hwparams, &mix_rate, NULL); CHECK_FAIL(status < 0); - int latency = GLOBAL_DEF("audio/output_latency", 25); - buffer_size = closest_power_of_2(latency * mix_rate / 1000); + // In ALSA the period size seems to be the one that will determine the actual latency + // Ref: https://www.alsa-project.org/main/index.php/FramesPeriods + unsigned int periods = 2; + int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY); + buffer_frames = closest_power_of_2(latency * mix_rate / 1000); + buffer_size = buffer_frames * periods; + period_size = buffer_frames; // set buffer size from project settings status = snd_pcm_hw_params_set_buffer_size_near(pcm_handle, hwparams, &buffer_size); CHECK_FAIL(status < 0); - // make period size 1/8 - period_size = buffer_size >> 3; status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, NULL); CHECK_FAIL(status < 0); - unsigned int periods = 2; + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("audio buffer frames: " + itos(period_size) + " calculated latency: " + itos(period_size * 1000 / mix_rate) + "ms"); + } + status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL); CHECK_FAIL(status < 0); diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h index 83601be41b..c76ec0da61 100644 --- a/drivers/alsa/audio_driver_alsa.h +++ b/drivers/alsa/audio_driver_alsa.h @@ -51,6 +51,7 @@ class AudioDriverALSA : public AudioDriver { unsigned int mix_rate; SpeakerMode speaker_mode; + snd_pcm_uframes_t buffer_frames; snd_pcm_uframes_t buffer_size; snd_pcm_uframes_t period_size; int channels; diff --git a/drivers/convex_decomp/b2d_decompose.cpp b/drivers/convex_decomp/b2d_decompose.cpp index 14ab4d1072..97d312983f 100644 --- a/drivers/convex_decomp/b2d_decompose.cpp +++ b/drivers/convex_decomp/b2d_decompose.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* b2d_decompose.cpp */ +/* b2d_decompose.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ diff --git a/drivers/coreaudio/SCsub b/drivers/coreaudio/SCsub new file mode 100644 index 0000000000..233593b0f9 --- /dev/null +++ b/drivers/coreaudio/SCsub @@ -0,0 +1,8 @@ +#!/usr/bin/env python + +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 new file mode 100644 index 0000000000..c531d6af9d --- /dev/null +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -0,0 +1,315 @@ +/*************************************************************************/ +/* audio_driver_coreaudio.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 COREAUDIO_ENABLED + +#include "audio_driver_coreaudio.h" +#include "core/project_settings.h" +#include "os/os.h" + +#define kOutputBus 0 + +#ifdef OSX_ENABLED +static OSStatus outputDeviceAddressCB(AudioObjectID inObjectID, UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses, void *__nullable inClientData) { + AudioDriverCoreAudio *driver = (AudioDriverCoreAudio *)inClientData; + + driver->reopen(); + + return noErr; +} +#endif + +Error AudioDriverCoreAudio::initDevice() { + 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, &audio_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + + AudioStreamBasicDescription strdesc; + + zeromem(&strdesc, sizeof(strdesc)); + UInt32 size = sizeof(strdesc); + result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kOutputBus, &strdesc, &size); + ERR_FAIL_COND_V(result != noErr, FAILED); + + switch (strdesc.mChannelsPerFrame) { + case 2: // Stereo + case 4: // Surround 3.1 + case 6: // Surround 5.1 + case 8: // Surround 7.1 + channels = strdesc.mChannelsPerFrame; + break; + + default: + // Unknown number of channels, default to stereo + channels = 2; + break; + } + + mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE); + + zeromem(&strdesc, sizeof(strdesc)); + strdesc.mFormatID = kAudioFormatLinearPCM; + strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; + strdesc.mChannelsPerFrame = 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(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + int latency = GLOBAL_DEF("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); + +#ifdef OSX_ENABLED + result = AudioUnitSetProperty(audio_unit, kAudioDevicePropertyBufferFrameSize, kAudioUnitScope_Global, kOutputBus, &buffer_frames, sizeof(UInt32)); + ERR_FAIL_COND_V(result != noErr, FAILED); +#endif + + buffer_size = buffer_frames * channels; + samples_in.resize(buffer_size); + + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("CoreAudio: detected " + itos(channels) + " channels"); + print_line("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); + } + + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + callback.inputProc = &AudioDriverCoreAudio::output_callback; + callback.inputProcRefCon = this; + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + result = AudioUnitInitialize(audio_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + + return OK; +} + +Error AudioDriverCoreAudio::finishDevice() { + OSStatus result; + + if (active) { + result = AudioOutputUnitStop(audio_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + + active = false; + } + + result = AudioUnitUninitialize(audio_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + + return OK; +} + +Error AudioDriverCoreAudio::init() { + OSStatus result; + + mutex = Mutex::create(); + active = false; + channels = 2; + +#ifdef OSX_ENABLED + outputDeviceAddress.mSelector = kAudioHardwarePropertyDefaultOutputDevice; + outputDeviceAddress.mScope = kAudioObjectPropertyScopeGlobal; + outputDeviceAddress.mElement = kAudioObjectPropertyElementMaster; + + result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); + ERR_FAIL_COND_V(result != noErr, FAILED); +#endif + + return initDevice(); +}; + +Error AudioDriverCoreAudio::reopen() { + bool restart = false; + + lock(); + + if (active) { + restart = true; + } + + Error err = finishDevice(); + if (err != OK) { + ERR_PRINT("finishDevice failed"); + unlock(); + return err; + } + + err = initDevice(); + if (err != OK) { + ERR_PRINT("initDevice failed"); + unlock(); + return err; + } + + if (restart) { + start(); + } + + unlock(); + + return OK; +} + +OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData) { + + AudioDriverCoreAudio *ad = (AudioDriverCoreAudio *)inRefCon; + + if (!ad->active || !ad->try_lock()) { + for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) { + AudioBuffer *abuf = &ioData->mBuffers[i]; + zeromem(abuf->mData, abuf->mDataByteSize); + }; + return 0; + }; + + for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) { + + AudioBuffer *abuf = &ioData->mBuffers[i]; + int frames_left = inNumberFrames; + int16_t *out = (int16_t *)abuf->mData; + + while (frames_left) { + + int frames = MIN(frames_left, ad->buffer_frames); + ad->audio_server_process(frames, ad->samples_in.ptr()); + + for (int j = 0; j < frames * ad->channels; j++) { + + out[j] = ad->samples_in[j] >> 16; + } + + frames_left -= frames; + out += frames * ad->channels; + }; + }; + + ad->unlock(); + + return 0; +}; + +void AudioDriverCoreAudio::start() { + if (!active) { + OSStatus result = AudioOutputUnitStart(audio_unit); + if (result != noErr) { + ERR_PRINT("AudioOutputUnitStart failed"); + } else { + active = true; + } + } +}; + +int AudioDriverCoreAudio::get_mix_rate() const { + return mix_rate; +}; + +AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const { + return get_speaker_mode_by_total_channels(channels); +}; + +void AudioDriverCoreAudio::lock() { + if (mutex) + mutex->lock(); +}; + +void AudioDriverCoreAudio::unlock() { + if (mutex) + mutex->unlock(); +}; + +bool AudioDriverCoreAudio::try_lock() { + if (mutex) + return mutex->try_lock() == OK; + return true; +} + +void AudioDriverCoreAudio::finish() { + OSStatus result; + + finishDevice(); + +#ifdef OSX_ENABLED + result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &outputDeviceAddress, &outputDeviceAddressCB, this); + if (result != noErr) { + ERR_PRINT("AudioObjectRemovePropertyListener failed"); + } +#endif + + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); + if (result != noErr) { + ERR_PRINT("AudioUnitSetProperty failed"); + } + + if (mutex) { + memdelete(mutex); + mutex = NULL; + } +}; + +AudioDriverCoreAudio::AudioDriverCoreAudio() { + active = false; + mutex = NULL; + + mix_rate = 0; + channels = 2; + + buffer_size = 0; + buffer_frames = 0; + + samples_in.clear(); +}; + +AudioDriverCoreAudio::~AudioDriverCoreAudio(){}; + +#endif diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h new file mode 100644 index 0000000000..33b3ba93ec --- /dev/null +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -0,0 +1,89 @@ +/*************************************************************************/ +/* audio_driver_coreaudio.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 COREAUDIO_ENABLED + +#ifndef AUDIO_DRIVER_COREAUDIO_H +#define AUDIO_DRIVER_COREAUDIO_H + +#include "servers/audio_server.h" + +#include <AudioUnit/AudioUnit.h> +#ifdef OSX_ENABLED +#include <CoreAudio/AudioHardware.h> +#endif + +class AudioDriverCoreAudio : public AudioDriver { + + AudioComponentInstance audio_unit; +#ifdef OSX_ENABLED + AudioObjectPropertyAddress outputDeviceAddress; +#endif + bool active; + Mutex *mutex; + + int mix_rate; + unsigned int channels; + unsigned int buffer_frames; + unsigned int buffer_size; + + Vector<int32_t> samples_in; + + static OSStatus output_callback(void *inRefCon, + AudioUnitRenderActionFlags *ioActionFlags, + const AudioTimeStamp *inTimeStamp, + UInt32 inBusNumber, UInt32 inNumberFrames, + AudioBufferList *ioData); + + Error initDevice(); + Error finishDevice(); + +public: + const char *get_name() const { + return "CoreAudio"; + }; + + 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(); + + bool try_lock(); + Error reopen(); + + AudioDriverCoreAudio(); + ~AudioDriverCoreAudio(); +}; + +#endif + +#endif diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index 74e844836e..5d62d2f5a0 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -574,6 +574,16 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); Rect2 src_rect = (rect->flags & CANVAS_RECT_REGION) ? Rect2(rect->source.position * texpixel_size, rect->source.size * texpixel_size) : Rect2(0, 0, 1, 1); + Rect2 dst_rect = Rect2(rect->rect.position, rect->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 (rect->flags & CANVAS_RECT_FLIP_H) { src_rect.size.x *= -1; @@ -584,12 +594,12 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } if (rect->flags & CANVAS_RECT_TRANSPOSE) { - //err.. + dst_rect.size.x *= -1; // Encoding in the dst_rect.z uniform } state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); - state.canvas_shader.set_uniform(CanvasShaderGLES3::DST_RECT, Color(rect->rect.position.x, rect->rect.position.y, rect->rect.size.x, rect->rect.size.y)); + 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); @@ -601,8 +611,18 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur } } else { + Rect2 dst_rect = Rect2(rect->rect.position, rect->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(CanvasShaderGLES3::DST_RECT, Color(rect->rect.position.x, rect->rect.position.y, rect->rect.size.x, rect->rect.size.y)); + 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(0, 0, 1, 1)); state.canvas_shader.set_uniform(CanvasShaderGLES3::CLIP_RECT_UV, false); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -1114,6 +1134,10 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons _copy_texscreen(Rect2()); } + if (shader_ptr->canvas_item.uses_time) { + VisualServerRaster::redraw_request(); + } + state.canvas_shader.set_custom_shader(shader_ptr->custom_code_id); state.canvas_shader.bind(); @@ -1214,11 +1238,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons last_blend_mode = blend_mode; } - 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_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.final_transform = ci->final_transform; state.extra_matrix = Transform2D(); @@ -1287,6 +1307,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons 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; } @@ -1337,6 +1358,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons 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); diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index f4dd9682a1..8ec988bec1 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* rasterizer_storage_gles3.cpp */ +/* rasterizer_scene_gles3.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -28,10 +28,11 @@ /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ /*************************************************************************/ #include "rasterizer_scene_gles3.h" - +#include "math_funcs.h" #include "os/os.h" #include "project_settings.h" #include "rasterizer_canvas_gles3.h" +#include "servers/visual/visual_server_raster.h" #ifndef GLES_OVER_GL #define glClearDepth glClearDepthf @@ -247,7 +248,7 @@ bool RasterizerSceneGLES3::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int qidx = p_in_quadrants[i]; - if (shadow_atlas->quadrants[qidx].subdivision == p_current_subdiv) { + if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) { return false; } @@ -257,7 +258,7 @@ bool RasterizerSceneGLES3::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int found_free_idx = -1; //found a free one int found_used_idx = -1; //found existing one, must steal it - uint64_t min_pass; // pass of the existing one, try to use the least recently used one (LRU fashion) + uint64_t min_pass = 0; // pass of the existing one, try to use the least recently used one (LRU fashion) for (int j = 0; j < sc; j++) { if (!sarr[j].owner.is_valid()) { @@ -349,7 +350,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; - bool should_realloc = shadow_atlas->quadrants[q].subdivision != best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); + bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec); bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version; if (!should_realloc) { @@ -378,6 +379,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in sh->owner = p_light_intance; sh->alloc_tick = tick; sh->version = p_light_version; + li->shadow_atlases.insert(p_atlas); //make new key key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; @@ -413,6 +415,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in sh->owner = p_light_intance; sh->alloc_tick = tick; sh->version = p_light_version; + li->shadow_atlases.insert(p_atlas); //make new key uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT; @@ -554,7 +557,7 @@ void RasterizerSceneGLES3::reflection_atlas_set_subdivision(RID p_ref_atlas, int ReflectionAtlas *reflection_atlas = reflection_atlas_owner.getornull(p_ref_atlas); ERR_FAIL_COND(!reflection_atlas); - uint32_t subdiv = next_power_of_2(p_subdiv); + int subdiv = next_power_of_2(p_subdiv); if (subdiv & 0xaaaaaaaa) { //sqrt(subdiv) must be integer subdiv <<= 1; } @@ -798,12 +801,12 @@ void RasterizerSceneGLES3::environment_set_sky(RID p_env, RID p_sky) { env->sky = p_sky; } -void RasterizerSceneGLES3::environment_set_sky_scale(RID p_env, float p_scale) { +void RasterizerSceneGLES3::environment_set_sky_custom_fov(RID p_env, float p_scale) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); - env->sky_scale = p_scale; + env->sky_custom_fov = p_scale; } void RasterizerSceneGLES3::environment_set_bg_color(RID p_env, const Color &p_color) { @@ -892,7 +895,7 @@ void RasterizerSceneGLES3::environment_set_ssr(RID p_env, bool p_enable, int p_m env->ssr_roughness = p_roughness; } -void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, bool p_blur) { +void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -906,6 +909,8 @@ void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float env->ssao_light_affect = p_light_affect; env->ssao_color = p_color; env->ssao_filter = p_blur; + env->ssao_quality = p_quality; + env->ssao_bilateral_sharpness = p_bilateral_sharpness; } void RasterizerSceneGLES3::environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) { @@ -1100,15 +1105,15 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m state.current_line_width = p_material->line_width; } - if (state.current_depth_test != (!p_material->shader->spatial.ontop)) { - if (p_material->shader->spatial.ontop) { + if (state.current_depth_test != (!p_material->shader->spatial.no_depth_test)) { + if (p_material->shader->spatial.no_depth_test) { glDisable(GL_DEPTH_TEST); } else { glEnable(GL_DEPTH_TEST); } - state.current_depth_test = !p_material->shader->spatial.ontop; + state.current_depth_test = !p_material->shader->spatial.no_depth_test; } if (state.current_depth_draw != p_material->shader->spatial.depth_draw_mode) { @@ -1129,9 +1134,9 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m state.current_depth_draw = p_material->shader->spatial.depth_draw_mode; } -//glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); + //glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); -/* + /* if (p_material->flags[VS::MATERIAL_FLAG_WIREFRAME]) glPolygonMode(GL_FRONT_AND_BACK,GL_LINE); else @@ -1939,6 +1944,7 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ bool prev_use_instancing = false; storage->info.render.draw_call_count += p_element_count; + bool prev_opaque_prepass = false; for (int i = 0; i < p_element_count; i++) { @@ -2072,6 +2078,13 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ } } + bool use_opaque_prepass = e->sort_key & RenderList::SORT_KEY_OPAQUE_PRE_PASS; + + if (use_opaque_prepass != prev_opaque_prepass) { + state.scene_shader.set_conditional(SceneShaderGLES3::USE_OPAQUE_PREPASS, use_opaque_prepass); + rebind = true; + } + bool use_instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH || e->instance->base_type == VS::INSTANCE_PARTICLES; if (use_instancing != prev_use_instancing) { @@ -2127,10 +2140,10 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ prev_shading = shading; prev_skeleton = skeleton; prev_use_instancing = use_instancing; + prev_opaque_prepass = use_opaque_prepass; first = false; } - glFrontFace(GL_CW); glBindVertexArray(0); state.scene_shader.set_conditional(SceneShaderGLES3::USE_INSTANCING, false); @@ -2148,9 +2161,10 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ state.scene_shader.set_conditional(SceneShaderGLES3::USE_GI_PROBES, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_CONTACT_SHADOWS, false); state.scene_shader.set_conditional(SceneShaderGLES3::USE_VERTEX_LIGHTING, false); + state.scene_shader.set_conditional(SceneShaderGLES3::USE_OPAQUE_PREPASS, false); } -void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_shadow) { +void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_depth_pass) { RasterizerStorageGLES3::Material *m = NULL; RID m_src = p_instance->material_override.is_valid() ? p_instance->material_override : (p_material >= 0 ? p_instance->materials[p_material] : p_geometry->material); @@ -2182,22 +2196,21 @@ void RasterizerSceneGLES3::_add_geometry(RasterizerStorageGLES3::Geometry *p_geo ERR_FAIL_COND(!m); - _add_geometry_with_material(p_geometry, p_instance, p_owner, m, p_shadow); + _add_geometry_with_material(p_geometry, p_instance, p_owner, m, p_depth_pass); while (m->next_pass.is_valid()) { m = storage->material_owner.getornull(m->next_pass); if (!m || !m->shader || !m->shader->valid) break; - _add_geometry_with_material(p_geometry, p_instance, p_owner, m, p_shadow); + _add_geometry_with_material(p_geometry, p_instance, p_owner, m, p_depth_pass); } } -void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, RasterizerStorageGLES3::Material *p_material, bool p_shadow) { +void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, RasterizerStorageGLES3::Material *p_material, bool p_depth_pass) { bool has_base_alpha = (p_material->shader->spatial.uses_alpha && !p_material->shader->spatial.uses_alpha_scissor) || p_material->shader->spatial.uses_screen_texture; - bool has_blend_alpha = p_material->shader->spatial.blend_mode != RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX || p_material->shader->spatial.ontop; + bool has_blend_alpha = p_material->shader->spatial.blend_mode != RasterizerStorageGLES3::Shader::Spatial::BLEND_MODE_MIX; bool has_alpha = has_base_alpha || has_blend_alpha; - bool shadow = false; bool mirror = p_instance->mirror; bool no_cull = false; @@ -2217,7 +2230,7 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G state.used_screen_texture = true; } - if (p_shadow) { + if (p_depth_pass) { if (has_blend_alpha || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) return; //bye @@ -2252,14 +2265,14 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G e->geometry->index = current_geometry_index++; } - if (!p_shadow && directional_light && (directional_light->light_ptr->cull_mask & e->instance->layer_mask) == 0) { + if (!p_depth_pass && directional_light && (directional_light->light_ptr->cull_mask & e->instance->layer_mask) == 0) { e->sort_key |= SORT_KEY_NO_DIRECTIONAL_FLAG; } e->sort_key |= uint64_t(e->geometry->index) << RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT; e->sort_key |= uint64_t(e->instance->base_type) << RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT; - if (!p_shadow) { + if (!p_depth_pass) { if (e->material->last_pass != render_pass) { e->material->last_pass = render_pass; @@ -2267,22 +2280,13 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G } e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT; - e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_DEPTH_LAYER_SHIFT; - - if (!has_blend_alpha && has_alpha && p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - - //if nothing exists, add this element as opaque too - RenderList::Element *oe = render_list.add_element(); - - if (!oe) - return; - - copymem(oe, e, sizeof(RenderList::Element)); - } + e->sort_key |= uint64_t(e->instance->depth_layer) << RenderList::SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT; if (e->instance->gi_probe_instances.size()) { e->sort_key |= SORT_KEY_GI_PROBES_FLAG; } + + e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT; } /* @@ -2300,28 +2304,25 @@ void RasterizerSceneGLES3::_add_geometry_with_material(RasterizerStorageGLES3::G //e->light_type=0xFF; // no lights! - if (shadow || p_material->shader->spatial.unshaded || state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_UNSHADED) { - + if (p_depth_pass || p_material->shader->spatial.unshaded || state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_UNSHADED) { e->sort_key |= SORT_KEY_UNSHADED_FLAG; } - if (!shadow && (p_material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading)) { + if (p_depth_pass && p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { + e->sort_key |= RenderList::SORT_KEY_OPAQUE_PRE_PASS; + } + + if (!p_depth_pass && (p_material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading)) { e->sort_key |= SORT_KEY_VERTEX_LIT_FLAG; } - if (!shadow && has_alpha && p_material->shader->spatial.depth_draw_mode == RasterizerStorageGLES3::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) { - //depth prepass for alpha - RenderList::Element *eo = render_list.add_element(); - - eo->instance = e->instance; - eo->geometry = e->geometry; - eo->material = e->material; - eo->sort_key = e->sort_key; + if (p_material->shader->spatial.uses_time) { + VisualServerRaster::redraw_request(); } } -void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_scale, 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) { if (!p_sky) return; @@ -2351,8 +2352,30 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C glDepthFunc(GL_LEQUAL); glColorMask(1, 1, 1, 1); + // Camera + CameraMatrix camera; + + if (p_custom_fov) { + + float near_plane = p_projection.get_z_near(); + float far_plane = p_projection.get_z_far(); + float aspect = p_projection.get_aspect(); + + camera.set_perspective(p_custom_fov, aspect, near_plane, far_plane); + + } else { + camera = p_projection; + } + float flip_sign = p_vflip ? -1 : 1; + /* + If matrix[2][0] or matrix[2][1] we're dealing with an asymmetrical projection matrix. This is the case for stereoscopic rendering (i.e. VR). + To ensure the image rendered is perspective correct we need to move some logic into the shader. For this the USE_ASYM_PANO option is introduced. + It also means the uv coordinates are ignored in this mode and we don't need our loop. + */ + bool asymmetrical = ((camera.matrix[2][0] != 0.0) || (camera.matrix[2][1] != 0.0)); + Vector3 vertices[8] = { Vector3(-1, -1 * flip_sign, 1), Vector3(0, 1, 0), @@ -2362,24 +2385,21 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C Vector3(1, 0, 0), Vector3(-1, 1 * flip_sign, 1), Vector3(0, 0, 0) - }; - //sky uv vectors - float vw, vh, zn; - p_projection.get_viewport_size(vw, vh); - zn = p_projection.get_z_near(); - - float scale = p_scale; - - for (int i = 0; i < 4; i++) { - - Vector3 uv = vertices[i * 2 + 1]; - uv.x = (uv.x * 2.0 - 1.0) * vw * scale; - uv.y = -(uv.y * 2.0 - 1.0) * vh * scale; - uv.z = -zn; - vertices[i * 2 + 1] = p_transform.basis.xform(uv).normalized(); - vertices[i * 2 + 1].z = -vertices[i * 2 + 1].z; + if (!asymmetrical) { + float vw, vh, zn; + camera.get_viewport_size(vw, vh); + zn = p_projection.get_z_near(); + + for (int i = 0; i < 4; i++) { + Vector3 uv = vertices[i * 2 + 1]; + uv.x = (uv.x * 2.0 - 1.0) * vw; + uv.y = -(uv.y * 2.0 - 1.0) * vh; + uv.z = -zn; + vertices[i * 2 + 1] = p_transform.basis.xform(uv).normalized(); + vertices[i * 2 + 1].z = -vertices[i * 2 + 1].z; + } } glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts); @@ -2388,16 +2408,24 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C glBindVertexArray(state.sky_array); - storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, true); + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_ASYM_PANO, asymmetrical); + 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); + 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]); + ///@TODO I couldn't get mat3 + p_transform.basis to work, that would be better here. + storage->shaders.copy.set_uniform(CopyShaderGLES3::PANO_TRANSFORM, p_transform); + } glDrawArrays(GL_TRIANGLE_FAN, 0, 4); glBindVertexArray(0); glColorMask(1, 1, 1, 1); + storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_ASYM_PANO, false); storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_MULTIPLIER, false); storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, false); } @@ -2406,6 +2434,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr //store camera into ubo store_camera(p_cam_projection, state.ubo_data.projection_matrix); + store_camera(p_cam_projection.inverse(), state.ubo_data.inv_projection_matrix); store_transform(p_cam_transform, state.ubo_data.camera_matrix); store_transform(p_cam_transform.affine_inverse(), state.ubo_data.camera_inverse_matrix); @@ -2523,9 +2552,10 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform float sign = li->light_ptr->negative ? -1 : 1; Color linear_col = li->light_ptr->color.to_linear(); - ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + //compensate normalized diffuse range by multiplying by PI + ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; + ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; + ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; ubo_data.light_color_energy[3] = 0; //omni, keep at 0 @@ -2541,8 +2571,8 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform ubo_data.light_direction_attenuation[3] = 1.0; ubo_data.light_params[0] = 0; - ubo_data.light_params[1] = li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; - ubo_data.light_params[2] = 0; + ubo_data.light_params[1] = 0; + ubo_data.light_params[2] = li->light_ptr->param[VS::LIGHT_PARAM_SPECULAR]; ubo_data.light_params[3] = 0; Color shadow_color = li->light_ptr->shadow_color.to_linear(); @@ -2601,7 +2631,7 @@ void RasterizerSceneGLES3::_setup_directional_light(int p_index, const Transform } } - ubo_data.shadow_split_offsets[j] = 1.0 / li->shadow_transform[j].split; + ubo_data.shadow_split_offsets[j] = li->shadow_transform[j].split; Transform modelview = (p_camera_inverse_transform * li->shadow_transform[j].transform).inverse(); @@ -2663,9 +2693,9 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result, int p_light_c float sign = li->light_ptr->negative ? -1 : 1; Color linear_col = li->light_ptr->color.to_linear(); - ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; + ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; + ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; ubo_data.light_color_energy[3] = 0; Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); @@ -2700,7 +2730,7 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result, int p_light_c uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - ERR_CONTINUE(shadow >= shadow_atlas->quadrants[quadrant].shadows.size()); + ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); uint32_t atlas_size = shadow_atlas->size; uint32_t quadrant_size = atlas_size >> 1; @@ -2749,9 +2779,9 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result, int p_light_c float sign = li->light_ptr->negative ? -1 : 1; Color linear_col = li->light_ptr->color.to_linear(); - ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; - ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY]; + ubo_data.light_color_energy[0] = linear_col.r * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; + ubo_data.light_color_energy[1] = linear_col.g * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; + ubo_data.light_color_energy[2] = linear_col.b * sign * li->light_ptr->param[VS::LIGHT_PARAM_ENERGY] * Math_PI; ubo_data.light_color_energy[3] = 0; Vector3 pos = p_camera_inverse_transform.xform(li->transform.origin); @@ -2787,7 +2817,7 @@ void RasterizerSceneGLES3::_setup_lights(RID *p_light_cull_result, int p_light_c uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - ERR_CONTINUE(shadow >= shadow_atlas->quadrants[quadrant].shadows.size()); + ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size()); uint32_t atlas_size = shadow_atlas->size; uint32_t quadrant_size = atlas_size >> 1; @@ -3030,7 +3060,7 @@ void RasterizerSceneGLES3::_copy_texture_to_front_buffer(GLuint p_texture) { storage->shaders.copy.set_conditional(CopyShaderGLES3::DISABLE_ALPHA, false); } -void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_shadow) { +void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass) { current_geometry_index = 0; current_material_index = 0; @@ -3055,7 +3085,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p int mat_idx = inst->materials[i].is_valid() ? i : -1; RasterizerStorageGLES3::Surface *s = mesh->surfaces[i]; - _add_geometry(s, inst, NULL, mat_idx, p_shadow); + _add_geometry(s, inst, NULL, mat_idx, p_depth_pass); } //mesh->last_pass=frame; @@ -3078,7 +3108,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p for (int i = 0; i < ssize; i++) { RasterizerStorageGLES3::Surface *s = mesh->surfaces[i]; - _add_geometry(s, inst, multi_mesh, -1, p_shadow); + _add_geometry(s, inst, multi_mesh, -1, p_depth_pass); } } break; @@ -3087,7 +3117,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p RasterizerStorageGLES3::Immediate *immediate = storage->immediate_owner.getptr(inst->base); ERR_CONTINUE(!immediate); - _add_geometry(immediate, inst, NULL, -1, p_shadow); + _add_geometry(immediate, inst, NULL, -1, p_depth_pass); } break; case VS::INSTANCE_PARTICLES: { @@ -3109,7 +3139,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p for (int j = 0; j < ssize; j++) { RasterizerStorageGLES3::Surface *s = mesh->surfaces[j]; - _add_geometry(s, inst, particles, -1, p_shadow); + _add_geometry(s, inst, particles, -1, p_depth_pass); } } @@ -3158,6 +3188,15 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glDisable(GL_CULL_FACE); glDisable(GL_BLEND); + if (env->ssao_enabled || env->ssr_enabled) { + + //copy normal and roughness to effect buffer + glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); + glReadBuffer(GL_COLOR_ATTACHMENT2); + glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->buffers.effect_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); + } + if (env->ssao_enabled) { //copy diffuse to front buffer glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); @@ -3176,6 +3215,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ for (int i = 0; i < storage->frame.current_rt->effects.ssao.depth_mipmap_fbos.size(); i++) { state.ssao_minify_shader.set_conditional(SsaoMinifyShaderGLES3::MINIFY_START, i == 0); + state.ssao_minify_shader.set_conditional(SsaoMinifyShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); state.ssao_minify_shader.bind(); state.ssao_minify_shader.set_uniform(SsaoMinifyShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); state.ssao_minify_shader.set_uniform(SsaoMinifyShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); @@ -3205,6 +3245,9 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glDepthFunc(GL_GREATER); // do SSAO! state.ssao_shader.set_conditional(SsaoShaderGLES3::ENABLE_RADIUS2, env->ssao_radius2 > 0.001); + state.ssao_shader.set_conditional(SsaoShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); + state.ssao_shader.set_conditional(SsaoShaderGLES3::SSAO_QUALITY_LOW, env->ssao_quality == VS::ENV_SSAO_QUALITY_LOW); + state.ssao_shader.set_conditional(SsaoShaderGLES3::SSAO_QUALITY_HIGH, env->ssao_quality == VS::ENV_SSAO_QUALITY_HIGH); state.ssao_shader.bind(); state.ssao_shader.set_uniform(SsaoShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); state.ssao_shader.set_uniform(SsaoShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); @@ -3257,6 +3300,9 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::CAMERA_Z_FAR, p_cam_projection.get_z_far()); state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::CAMERA_Z_NEAR, p_cam_projection.get_z_near()); + state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::EDGE_SHARPNESS, env->ssao_bilateral_sharpness); + state.ssao_blur_shader.set_uniform(SsaoBlurShaderGLES3::FILTER_SCALE, int(env->ssao_filter)); + GLint axis[2] = { i, 1 - i }; glUniform2iv(state.ssao_blur_shader.get_uniform(SsaoBlurShaderGLES3::AXIS), 1, axis); glUniform2iv(state.ssao_blur_shader.get_uniform(SsaoBlurShaderGLES3::SCREEN_SIZE), 1, ss); @@ -3265,6 +3311,8 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->effects.ssao.blur_red[i]); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->depth); + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->buffers.effect); glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->effects.ssao.blur_fbo[1 - i]); if (i == 0) { glClearBufferfv(GL_COLOR, 0, white.components); // specular @@ -3314,6 +3362,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->effects.ssao.blur_fbo[0]); 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_LINEAR); + state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_11_SAMPLES, subsurface_scatter_quality == SSS_QUALITY_LOW); state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_17_SAMPLES, subsurface_scatter_quality == SSS_QUALITY_MEDIUM); state.sss_shader.set_conditional(SubsurfScatteringShaderGLES3::USE_25_SAMPLES, subsurface_scatter_quality == SSS_QUALITY_HIGH); @@ -3355,12 +3404,6 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ if (env->ssr_enabled) { - //copy normal and roughness to effect buffer - glBindFramebuffer(GL_READ_FRAMEBUFFER, storage->frame.current_rt->buffers.fbo); - glReadBuffer(GL_COLOR_ATTACHMENT2); - glBindFramebuffer(GL_DRAW_FRAMEBUFFER, storage->frame.current_rt->buffers.effect_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); - //blur diffuse into effect mipmaps using separatable convolution //storage->shaders.copy.set_conditional(CopyShaderGLES3::GAUSSIAN_HORIZONTAL,true); _blur_effect_buffer(); @@ -3368,6 +3411,7 @@ void RasterizerSceneGLES3::_render_mrts(Environment *env, const CameraMatrix &p_ //perform SSR state.ssr_shader.set_conditional(ScreenSpaceReflectionShaderGLES3::REFLECT_ROUGHNESS, env->ssr_roughness); + state.ssr_shader.set_conditional(ScreenSpaceReflectionShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); state.ssr_shader.bind(); @@ -3521,6 +3565,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p int vp_h = storage->frame.current_rt->height; int vp_w = storage->frame.current_rt->width; + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_FAR_BLUR, true); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_LOW); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, env->dof_blur_far_quality == VS::ENV_DOF_BLUR_QUALITY_MEDIUM); @@ -3563,6 +3608,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, false); composite_from = storage->frame.current_rt->effects.mip_maps[0].color; } @@ -3575,6 +3621,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p int vp_h = storage->frame.current_rt->height; int vp_w = storage->frame.current_rt->width; + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, p_cam_projection.is_orthogonal()); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_BLUR, true); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_NEAR_FIRST_TAP, true); @@ -3650,6 +3697,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_LOW, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_MEDIUM, false); state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::DOF_QUALITY_HIGH, false); + state.effect_blur_shader.set_conditional(EffectBlurShaderGLES3::USE_ORTHOGONAL_PROJECTION, false); composite_from = storage->frame.current_rt->effects.mip_maps[0].color; } @@ -3741,6 +3789,8 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p SWAP(exposure_shrink[exposure_shrink.size() - 1].color, storage->frame.current_rt->exposure.color); glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height); + + VisualServerRaster::redraw_request(); //if using auto exposure, redraw must happen } int max_glow_level = -1; @@ -3973,6 +4023,8 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const state.ubo_data.shadow_dual_paraboloid_render_side = 0; state.ubo_data.shadow_dual_paraboloid_render_zfar = 0; + p_cam_projection.get_viewport_size(state.ubo_data.viewport_size[0], state.ubo_data.viewport_size[1]); + if (storage->frame.current_rt) { state.ubo_data.screen_pixel_size[0] = 1.0 / storage->frame.current_rt->width; state.ubo_data.screen_pixel_size[1] = 1.0 / storage->frame.current_rt->height; @@ -4157,7 +4209,7 @@ 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_SKY) { + } else if (env->bg_mode == VS::ENV_BG_SKY || env->bg_mode == VS::ENV_BG_COLOR_SKY) { sky = storage->sky_owner.getornull(env->sky); @@ -4165,6 +4217,9 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const env_radiance_tex = sky->radiance; } storage->frame.clear_request = false; + if (env->bg_mode == VS::ENV_BG_COLOR_SKY) { + clear_color = env->bg_color.to_linear(); + } } else { storage->frame.clear_request = false; @@ -4246,7 +4301,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glBindFramebuffer(GL_FRAMEBUFFER,storage->frame.current_rt->buffers.fbo); //switch to alpha fbo for sky, only diffuse/ambient matters */ - _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_scale, env->bg_energy); + _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy); } //_render_list_forward(&alpha_render_list,camera_transform,camera_transform_inverse,camera_projection,false,fragment_lighting,true); @@ -4282,7 +4337,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glEnable(GL_DEPTH_TEST); glDisable(GL_SCISSOR_TEST); - render_list.sort_by_reverse_depth(true); + render_list.sort_by_reverse_depth_and_priority(true); if (state.directional_light_count == 0) { directional_light = NULL; @@ -4445,9 +4500,10 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ } } + float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]); zfar = light->param[VS::LIGHT_PARAM_RANGE]; - bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS] * light_instance->shadow_transform[p_pass].bias_scale; - normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * light_instance->shadow_transform[p_pass].bias_scale; + 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; @@ -4466,7 +4522,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK; - ERR_FAIL_INDEX(shadow, shadow_atlas->quadrants[quadrant].shadows.size()); + ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size()); uint32_t quadrant_size = shadow_atlas->size >> 1; @@ -4998,6 +5054,8 @@ void RasterizerSceneGLES3::initialize() { } state.debug_draw = VS::VIEWPORT_DEBUG_DRAW_DISABLED; + + glFrontFace(GL_CW); } void RasterizerSceneGLES3::iteration() { diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index 659408b455..69b43c7813 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -110,6 +110,7 @@ public: struct SceneDataUBO { //this is a std140 compatible struct. Please read the OpenGL 3.3 Specificaiton spec before doing any changes float projection_matrix[16]; + float inv_projection_matrix[16]; float camera_inverse_matrix[16]; float camera_matrix[16]; float ambient_light_color[4]; @@ -123,6 +124,7 @@ public: float z_slope_scale; float shadow_dual_paraboloid_render_zfar; float shadow_dual_paraboloid_render_side; + float viewport_size[2]; float screen_pixel_size[2]; float shadow_atlas_pixel_size[2]; float shadow_directional_pixel_size[2]; @@ -142,7 +144,7 @@ public: float fog_height_min; float fog_height_max; float fog_height_curve; - uint8_t padding[8]; + // make sure this struct is padded to be a multiple of 16 bytes for webgl } ubo_data; @@ -244,7 +246,7 @@ public: GLuint fbo_id[6]; GLuint cubemap; - int size; + uint32_t size; }; Vector<ShadowCubeMap> shadow_cubemaps; @@ -351,7 +353,7 @@ public: VS::EnvironmentBG bg_mode; RID sky; - float sky_scale; + float sky_custom_fov; Color bg_color; float bg_energy; @@ -378,7 +380,9 @@ public: float ssao_bias; float ssao_light_affect; Color ssao_color; - bool ssao_filter; + VS::EnvironmentSSAOQuality ssao_quality; + float ssao_bilateral_sharpness; + VS::EnvironmentSSAOBlur ssao_filter; bool glow_enabled; int glow_levels; @@ -434,7 +438,7 @@ public: Environment() { bg_mode = VS::ENV_BG_CLEAR_COLOR; - sky_scale = 1.0; + sky_custom_fov = 0.0; bg_energy = 1.0; sky_ambient = 0; ambient_energy = 1.0; @@ -455,7 +459,9 @@ public: ssao_radius2 = 0.0; ssao_bias = 0.01; ssao_light_affect = 0; - ssao_filter = true; + 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; @@ -519,7 +525,7 @@ 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_scale(RID p_env, float p_scale); + virtual void environment_set_sky_custom_fov(RID p_env, float p_scale); 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); @@ -531,7 +537,7 @@ public: 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); - virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_radius2, float p_intensity2, float p_intensity, float p_bias, float p_light_affect, const Color &p_color, bool p_blur); + virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness); virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale); @@ -645,17 +651,26 @@ public: MAX_LIGHTS = 4096, MAX_REFLECTIONS = 1024, - SORT_KEY_DEPTH_LAYER_SHIFT = 60, + SORT_KEY_PRIORITY_SHIFT = 56, + SORT_KEY_PRIORITY_MASK = 0xFF, + //depth layer for opaque (56-52) + SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT = 52, + SORT_KEY_OPAQUE_DEPTH_LAYER_MASK = 0xF, //64 bits unsupported in MSVC -#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 59) -#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 58) -#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 57) -#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 56) - SORT_KEY_SHADING_SHIFT = 56, +#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 51) +#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 50) +#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 49) +#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 48) + SORT_KEY_SHADING_SHIFT = 48, SORT_KEY_SHADING_MASK = 15, - SORT_KEY_MATERIAL_INDEX_SHIFT = 40, - SORT_KEY_GEOMETRY_INDEX_SHIFT = 20, - SORT_KEY_GEOMETRY_TYPE_SHIFT = 15, + //48-32 material index + SORT_KEY_MATERIAL_INDEX_SHIFT = 32, + //32-12 geometry index + SORT_KEY_GEOMETRY_INDEX_SHIFT = 12, + //bits 12-8 geometry type + SORT_KEY_GEOMETRY_TYPE_SHIFT = 8, + //bits 0-7 for flags + SORT_KEY_OPAQUE_PRE_PASS = 8, SORT_KEY_CULL_DISABLED_FLAG = 4, SORT_KEY_SKELETON_FLAG = 2, SORT_KEY_MIRROR_FLAG = 1 @@ -721,16 +736,22 @@ public: } } - struct SortByReverseDepth { + struct SortByReverseDepthAndPriority { _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const { - return A->instance->depth > B->instance->depth; + uint32_t layer_A = uint32_t(A->sort_key >> SORT_KEY_PRIORITY_SHIFT); + uint32_t layer_B = uint32_t(B->sort_key >> SORT_KEY_PRIORITY_SHIFT); + if (layer_A == layer_B) { + return A->instance->depth > B->instance->depth; + } else { + return layer_A < layer_B; + } } }; - void sort_by_reverse_depth(bool p_alpha) { //used for alpha + void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha - SortArray<Element *, SortByReverseDepth> sorter; + SortArray<Element *, SortByReverseDepthAndPriority> sorter; if (p_alpha) { sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count); } else { @@ -791,11 +812,11 @@ public: void _render_list(RenderList::Element **p_elements, int p_element_count, const Transform &p_view_transform, const CameraMatrix &p_projection, GLuint p_base_env, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add, bool p_directional_shadows); - _FORCE_INLINE_ void _add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_shadow); + _FORCE_INLINE_ void _add_geometry(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, int p_material, bool p_depth_pass); - _FORCE_INLINE_ void _add_geometry_with_material(RasterizerStorageGLES3::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES3::GeometryOwner *p_owner, RasterizerStorageGLES3::Material *p_material, bool p_shadow); + _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); - void _draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_scale, 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); void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform); void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transform, bool p_use_shadows); @@ -806,7 +827,7 @@ public: void _copy_to_front_buffer(Environment *env); void _copy_texture_to_front_buffer(GLuint p_texture); //used for debug - void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_shadow); + void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass); void _blur_effect_buffer(); void _render_mrts(Environment *env, const CameraMatrix &p_cam_projection); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index c5c9140874..296d945cda 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -165,7 +165,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ } break; case Image::FORMAT_RGB8: { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? GL_SRGB8 : GL_RGB8; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8 : GL_RGB8; r_gl_format = GL_RGB; r_gl_type = GL_UNSIGNED_BYTE; srgb = true; @@ -174,7 +174,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ case Image::FORMAT_RGBA8: { r_gl_format = GL_RGBA; - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? GL_SRGB8_ALPHA8 : GL_RGBA8; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8_ALPHA8 : GL_RGBA8; r_gl_type = GL_UNSIGNED_BYTE; srgb = true; @@ -254,7 +254,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.s3tc_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT1_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -270,7 +270,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.s3tc_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -286,7 +286,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.s3tc_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_NV : _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -331,7 +331,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.bptc_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM : _EXT_COMPRESSED_RGBA_BPTC_UNORM; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_BPTC_UNORM : _EXT_COMPRESSED_RGBA_BPTC_UNORM; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -371,7 +371,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.pvrtc_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT : _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT : _EXT_COMPRESSED_RGB_PVRTC_2BPPV1_IMG; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -386,7 +386,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.pvrtc_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT : _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT : _EXT_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -402,7 +402,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.pvrtc_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT : _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT : _EXT_COMPRESSED_RGB_PVRTC_4BPPV1_IMG; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -418,7 +418,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.pvrtc_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT : _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT : _EXT_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -503,7 +503,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.etc2_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB8_ETC2 : _EXT_COMPRESSED_RGB8_ETC2; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB8_ETC2 : _EXT_COMPRESSED_RGB8_ETC2; r_gl_format = GL_RGB; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -518,7 +518,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.etc2_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : _EXT_COMPRESSED_RGBA8_ETC2_EAC; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : _EXT_COMPRESSED_RGBA8_ETC2_EAC; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -533,7 +533,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ if (config.etc2_supported) { - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? _EXT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? _EXT_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : _EXT_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2; r_gl_format = GL_RGBA; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = true; @@ -560,7 +560,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_ } r_gl_format = GL_RGBA; - r_gl_internal_format = (config.srgb_decode_supported || p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR) ? GL_SRGB8_ALPHA8 : GL_RGBA8; + r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8_ALPHA8 : GL_RGBA8; r_gl_type = GL_UNSIGNED_BYTE; r_compressed = false; srgb = true; @@ -595,7 +595,6 @@ RID RasterizerStorageGLES3::texture_create() { void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags) { - int components; GLenum format; GLenum internal_format; GLenum type; @@ -686,7 +685,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p texture->ignore_mipmaps = compressed && !img->has_mipmaps(); - if (texture->flags & VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) + if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) glTexParameteri(texture->target, GL_TEXTURE_MIN_FILTER, config.use_fast_texture_filter ? GL_LINEAR_MIPMAP_NEAREST : GL_LINEAR_MIPMAP_LINEAR); else { if (texture->flags & VS::TEXTURE_FLAG_FILTER) { @@ -717,7 +716,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering } - if ((texture->flags & VS::TEXTURE_FLAG_REPEAT || texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT) && texture->target != GL_TEXTURE_CUBE_MAP) { + if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { if (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); @@ -770,15 +769,13 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p } } - int mipmaps = (texture->flags & VS::TEXTURE_FLAG_MIPMAPS && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; + int mipmaps = ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; int w = img->get_width(); int h = img->get_height(); int tsize = 0; - int block = Image::get_format_block_size(img->get_format()); - for (int i = 0; i < mipmaps; i++) { int size, ofs; @@ -789,10 +786,6 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p if (texture->compressed) { glPixelStorei(GL_UNPACK_ALIGNMENT, 4); - //this is not needed, as compressed takes the regular size, even if blocks extend it - //int bw = (w % block != 0) ? w + (block - w % block) : w; - //int bh = (h % block != 0) ? h + (block - h % block) : h; - int bw = w; int bh = h; @@ -820,7 +813,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p texture->stored_cube_sides |= (1 << p_cube_side); - if (texture->flags & VS::TEXTURE_FLAG_MIPMAPS && mipmaps == 1 && !texture->ignore_mipmaps && (!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides == (1 << 6) - 1)) { + if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides == (1 << 6) - 1)) { //generate mipmaps if they were requested and the image does not contain them glGenerateMipmap(texture->target); } else if (mipmaps > 1) { @@ -912,7 +905,7 @@ void RasterizerStorageGLES3::texture_set_flags(RID p_texture, uint32_t p_flags) uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP; texture->flags = p_flags | cube; // can't remove a cube from being a cube - if ((texture->flags & VS::TEXTURE_FLAG_REPEAT || texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT) && texture->target != GL_TEXTURE_CUBE_MAP) { + if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) { if (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT) { glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_MIRRORED_REPEAT); @@ -937,7 +930,7 @@ void RasterizerStorageGLES3::texture_set_flags(RID p_texture, uint32_t p_flags) } } - if (texture->flags & VS::TEXTURE_FLAG_MIPMAPS && !texture->ignore_mipmaps) { + if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && !texture->ignore_mipmaps) { if (!had_mipmaps && texture->mipmaps == 1) { glGenerateMipmap(texture->target); } @@ -1571,6 +1564,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->canvas_item.blend_mode = Shader::CanvasItem::BLEND_MODE_MIX; p_shader->canvas_item.uses_screen_texture = false; p_shader->canvas_item.uses_screen_uv = false; + p_shader->canvas_item.uses_time = false; shaders.actions_canvas.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_ADD); shaders.actions_canvas.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->canvas_item.blend_mode, Shader::CanvasItem::BLEND_MODE_MIX); @@ -1584,6 +1578,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { 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; shaders.actions_canvas.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->canvas_item.uses_screen_texture; + shaders.actions_canvas.usage_flag_pointers["TIME"] = &p_shader->canvas_item.uses_time; actions = &shaders.actions_canvas; actions->uniforms = &p_shader->uniforms; @@ -1599,8 +1594,9 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->spatial.uses_alpha_scissor = false; p_shader->spatial.uses_discard = false; p_shader->spatial.unshaded = false; - p_shader->spatial.ontop = false; + p_shader->spatial.no_depth_test = false; p_shader->spatial.uses_sss = false; + p_shader->spatial.uses_time = false; p_shader->spatial.uses_vertex_lighting = false; p_shader->spatial.uses_screen_texture = false; p_shader->spatial.uses_vertex = false; @@ -1621,7 +1617,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { shaders.actions_scene.render_mode_values["cull_disabled"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_DISABLED); shaders.actions_scene.render_mode_flags["unshaded"] = &p_shader->spatial.unshaded; - shaders.actions_scene.render_mode_flags["ontop"] = &p_shader->spatial.ontop; + shaders.actions_scene.render_mode_flags["depth_test_disable"] = &p_shader->spatial.no_depth_test; shaders.actions_scene.render_mode_flags["vertex_lighting"] = &p_shader->spatial.uses_vertex_lighting; @@ -1632,6 +1628,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"] = &p_shader->spatial.uses_sss; shaders.actions_scene.usage_flag_pointers["DISCARD"] = &p_shader->spatial.uses_discard; shaders.actions_scene.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->spatial.uses_screen_texture; + shaders.actions_scene.usage_flag_pointers["TIME"] = &p_shader->spatial.uses_time; shaders.actions_scene.write_flag_pointers["MODELVIEW_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection; shaders.actions_scene.write_flag_pointers["PROJECTION_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection; @@ -1948,6 +1945,17 @@ void RasterizerStorageGLES3::material_remove_instance_owner(RID p_material, Rast } } +void RasterizerStorageGLES3::material_set_render_priority(RID p_material, int priority) { + + ERR_FAIL_COND(priority < VS::MATERIAL_RENDER_PRIORITY_MIN); + ERR_FAIL_COND(priority > VS::MATERIAL_RENDER_PRIORITY_MAX); + + Material *material = material_owner.get(p_material); + ERR_FAIL_COND(!material); + + material->render_priority = priority; +} + _FORCE_INLINE_ static void _fill_std140_variant_ubo_value(ShaderLanguage::DataType type, const Variant &value, uint8_t *data, bool p_linear_color) { switch (type) { case ShaderLanguage::TYPE_BOOL: { @@ -2422,7 +2430,8 @@ void RasterizerStorageGLES3::_update_material(Material *material) { if (material->shader && material->shader->mode == VS::SHADER_SPATIAL) { - if (!material->shader->spatial.uses_alpha && material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX) { + 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))) { can_cast_shadow = true; } @@ -2465,7 +2474,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { glGenBuffers(1, &material->ubo_id); glBindBuffer(GL_UNIFORM_BUFFER, material->ubo_id); - glBufferData(GL_UNIFORM_BUFFER, material->shader->ubo_size, NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_UNIFORM_BUFFER, material->shader->ubo_size, NULL, GL_STATIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); material->ubo_size = material->shader->ubo_size; } @@ -3347,7 +3356,7 @@ Rect3 RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { for (int i = 0; i < mesh->surfaces.size(); i++) { Rect3 laabb; - if (mesh->surfaces[i]->format & VS::ARRAY_FORMAT_BONES && mesh->surfaces[i]->skeleton_bone_aabb.size()) { + 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 Rect3 *skbones = mesh->surfaces[i]->skeleton_bone_aabb.ptr(); @@ -3760,7 +3769,7 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances glGenBuffers(1, &multimesh->buffer); glBindBuffer(GL_ARRAY_BUFFER, multimesh->buffer); - glBufferData(GL_ARRAY_BUFFER, multimesh->data.size() * sizeof(float), NULL, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, multimesh->data.size() * sizeof(float), NULL, GL_STATIC_DRAW); glBindBuffer(GL_ARRAY_BUFFER, 0); } @@ -3963,7 +3972,7 @@ Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int ERR_FAIL_COND_V(multimesh->color_format == VS::MULTIMESH_COLOR_NONE, Color()); int stride = multimesh->color_floats + multimesh->xform_floats; - float *dataptr = &multimesh->data[stride * p_index + multimesh->color_floats]; + float *dataptr = &multimesh->data[stride * p_index + multimesh->xform_floats]; if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) { union { @@ -3971,6 +3980,8 @@ Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int float colf; } cu; + cu.colf = dataptr[0]; + return Color::hex(BSWAP32(cu.colu)); } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) { @@ -4448,6 +4459,7 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type) { light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3; light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6; light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1; + light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1; light->color = Color(1, 1, 1, 1); light->shadow = false; @@ -4457,6 +4469,7 @@ RID RasterizerStorageGLES3::light_create(VS::LightType p_type) { light->omni_shadow_mode = VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID; light->omni_shadow_detail = VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL; light->directional_blend_splits = false; + light->directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE; light->reverse_cull = false; light->version = 0; @@ -4609,6 +4622,22 @@ VS::LightDirectionalShadowMode RasterizerStorageGLES3::light_directional_get_sha return light->directional_shadow_mode; } +void RasterizerStorageGLES3::light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) { + + Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND(!light); + + light->directional_range_mode = p_range_mode; +} + +VS::LightDirectionalShadowDepthRangeMode RasterizerStorageGLES3::light_directional_get_shadow_depth_range_mode(RID p_light) const { + + const Light *light = light_owner.getornull(p_light); + ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE); + + return light->directional_range_mode; +} + VS::LightType RasterizerStorageGLES3::light_get_type(RID p_light) const { const Light *light = light_owner.getornull(p_light); @@ -5187,7 +5216,7 @@ void RasterizerStorageGLES3::particles_set_amount(RID p_particles, int p_amount) glBindVertexArray(particles->particle_vaos[i]); glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[i]); - glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, floats * sizeof(float), data, GL_STATIC_DRAW); for (int i = 0; i < 6; i++) { glEnableVertexAttribArray(i); @@ -6170,7 +6199,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { rt->buffers.effects_active = true; } - if (!rt->flags[RENDER_TARGET_NO_SAMPLING]) { + if (!rt->flags[RENDER_TARGET_NO_SAMPLING] && rt->width >= 2 && rt->height >= 2) { for (int i = 0; i < 2; i++) { @@ -6483,7 +6512,7 @@ void RasterizerStorageGLES3::canvas_light_occluder_set_polylines(RID p_occluder, 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_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, lc * 6 * sizeof(real_t), vw.ptr(), GL_STATIC_DRAW); } else { glBindBuffer(GL_ARRAY_BUFFER, co->vertex_id); @@ -6831,42 +6860,28 @@ int RasterizerStorageGLES3::get_captured_render_info(VS::RenderInfo p_info) { int RasterizerStorageGLES3::get_render_info(VS::RenderInfo p_info) { switch (p_info) { - case VS::INFO_OBJECTS_IN_FRAME: { - + case VS::INFO_OBJECTS_IN_FRAME: return info.render_final.object_count; - } break; - case VS::INFO_VERTICES_IN_FRAME: { - + case VS::INFO_VERTICES_IN_FRAME: return info.render_final.vertices_count; - } break; - case VS::INFO_MATERIAL_CHANGES_IN_FRAME: { + case VS::INFO_MATERIAL_CHANGES_IN_FRAME: return info.render_final.material_switch_count; - } break; - case VS::INFO_SHADER_CHANGES_IN_FRAME: { + case VS::INFO_SHADER_CHANGES_IN_FRAME: return info.render_final.shader_rebind_count; - } break; - case VS::INFO_SURFACE_CHANGES_IN_FRAME: { + case VS::INFO_SURFACE_CHANGES_IN_FRAME: return info.render_final.surface_switch_count; - } break; - case VS::INFO_DRAW_CALLS_IN_FRAME: { + case VS::INFO_DRAW_CALLS_IN_FRAME: return info.render_final.draw_call_count; - } break; - case VS::INFO_USAGE_VIDEO_MEM_TOTAL: { - + case VS::INFO_USAGE_VIDEO_MEM_TOTAL: return 0; //no idea - } break; - case VS::INFO_VIDEO_MEM_USED: { - + case VS::INFO_VIDEO_MEM_USED: return info.vertex_mem + info.texture_mem; - } break; - case VS::INFO_TEXTURE_MEM_USED: { - + case VS::INFO_TEXTURE_MEM_USED: return info.texture_mem; - } break; - case VS::INFO_VERTEX_MEM_USED: { - + case VS::INFO_VERTEX_MEM_USED: return info.vertex_mem; - } break; + default: + return 0; //no idea either } } diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index c74b127b23..6abc22b643 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -410,6 +410,7 @@ public: int light_mode; bool uses_screen_texture; bool uses_screen_uv; + bool uses_time; } canvas_item; @@ -444,11 +445,12 @@ public: bool uses_alpha; bool uses_alpha_scissor; bool unshaded; - bool ontop; + bool no_depth_test; bool uses_vertex; bool uses_discard; bool uses_sss; bool uses_screen_texture; + bool uses_time; bool writes_modelview_or_projection; bool uses_vertex_lighting; @@ -502,6 +504,7 @@ public: SelfList<Material> dirty_list; Vector<RID> textures; float line_width; + int render_priority; RID next_pass; @@ -523,6 +526,7 @@ public: ubo_id = 0; ubo_size = 0; last_pass = 0; + render_priority = 0; } }; @@ -550,6 +554,8 @@ public: virtual void material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); virtual void material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance); + virtual void material_set_render_priority(RID p_material, int priority); + void _update_material(Material *material); void update_dirty_materials(); @@ -873,6 +879,7 @@ public: VS::LightOmniShadowMode omni_shadow_mode; VS::LightOmniShadowDetail omni_shadow_detail; VS::LightDirectionalShadowMode directional_shadow_mode; + VS::LightDirectionalShadowDepthRangeMode directional_range_mode; bool directional_blend_splits; uint64_t version; }; @@ -900,6 +907,9 @@ public: virtual VS::LightDirectionalShadowMode light_directional_get_shadow_mode(RID p_light); virtual VS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light); + virtual void light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode); + virtual VS::LightDirectionalShadowDepthRangeMode light_directional_get_shadow_depth_range_mode(RID p_light) const; + virtual bool light_has_shadow(RID p_light) const; virtual VS::LightType light_get_type(RID p_light) const; diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index c308e9eddb..ad08c59de8 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -438,25 +438,43 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener SL::BlockNode *bnode = (SL::BlockNode *)p_node; //variables - code += _mktab(p_level - 1) + "{\n"; - for (Map<StringName, SL::BlockNode::Variable>::Element *E = bnode->variables.front(); E; E = E->next()) { - - code += _mktab(p_level) + _prestr(E->get().precision) + _typestr(E->get().type) + " " + _mkid(E->key()) + ";\n"; + if (!bnode->single_statement) { + code += _mktab(p_level - 1) + "{\n"; } for (int i = 0; i < bnode->statements.size(); i++) { String scode = _dump_node_code(bnode->statements[i], p_level, r_gen_code, p_actions, p_default_actions); - if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW) { - // FIXME: if (A || A) ? I am hesitant to delete one of them, could be copy-paste error. + if (bnode->statements[i]->type == SL::Node::TYPE_CONTROL_FLOW || bnode->single_statement) { code += scode; //use directly } else { code += _mktab(p_level) + scode + ";\n"; } } - code += _mktab(p_level - 1) + "}\n"; + if (!bnode->single_statement) { + code += _mktab(p_level - 1) + "}\n"; + } + + } break; + case SL::Node::TYPE_VARIABLE_DECLARATION: { + SL::VariableDeclarationNode *vdnode = (SL::VariableDeclarationNode *)p_node; + + String declaration = _prestr(vdnode->precision) + _typestr(vdnode->datatype); + for (int i = 0; i < vdnode->declarations.size(); i++) { + if (i > 0) { + declaration += ","; + } else { + declaration += " "; + } + declaration += _mkid(vdnode->declarations[i].name); + if (vdnode->declarations[i].initializer) { + declaration += "="; + declaration += _dump_node_code(vdnode->declarations[i].initializer, p_level, r_gen_code, p_actions, p_default_actions); + } + } + code += declaration; } break; case SL::Node::TYPE_VARIABLE: { SL::VariableNode *vnode = (SL::VariableNode *)p_node; @@ -600,6 +618,13 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener code += _mktab(p_level) + "while (" + _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions) + ")\n"; code += _dump_node_code(cfnode->blocks[0], p_level + 1, r_gen_code, p_actions, p_default_actions); + } else if (cfnode->flow_op == SL::FLOW_OP_FOR) { + + String left = _dump_node_code(cfnode->blocks[0], p_level, r_gen_code, p_actions, p_default_actions); + String middle = _dump_node_code(cfnode->expressions[0], p_level, r_gen_code, p_actions, p_default_actions); + String right = _dump_node_code(cfnode->expressions[1], p_level, r_gen_code, p_actions, p_default_actions); + code += _mktab(p_level) + "for (" + left + ";" + middle + ";" + right + ")\n"; + code += _dump_node_code(cfnode->blocks[1], p_level + 1, r_gen_code, p_actions, p_default_actions); } else if (cfnode->flow_op == SL::FLOW_OP_RETURN) { @@ -611,6 +636,12 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener } else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) { code = "discard;"; + } else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) { + + code = "continue;"; + } else if (cfnode->flow_op == SL::FLOW_OP_BREAK) { + + code = "break;"; } } break; @@ -669,9 +700,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { /** CANVAS ITEM SHADER **/ - actions[VS::SHADER_CANVAS_ITEM].renames["SRC_VERTEX"] = "vertex"; actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX"] = "outvec.xy"; - actions[VS::SHADER_CANVAS_ITEM].renames["VERTEX_COLOR"] = "vertex_color"; actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp"; actions[VS::SHADER_CANVAS_ITEM].renames["POINT_SIZE"] = "gl_PointSize"; @@ -680,6 +709,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_CANVAS_ITEM].renames["EXTRA_MATRIX"] == "extra_matrix"; 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"; actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal"; @@ -689,6 +719,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color"; actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture"; actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size"; + actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture"; actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_UV"] = "screen_uv"; actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_TEXTURE"] = "screen_texture"; actions[VS::SHADER_CANVAS_ITEM].renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size"; @@ -719,6 +750,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { 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"] = "inv_projection_matrix"; actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz"; @@ -734,10 +766,10 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { //builtins actions[VS::SHADER_SPATIAL].renames["TIME"] = "time"; - //actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"]=ShaderLanguage::TYPE_VEC2; + actions[VS::SHADER_SPATIAL].renames["VIEWPORT_SIZE"] = "viewport_size"; actions[VS::SHADER_SPATIAL].renames["FRAGCOORD"] = "gl_FragCoord"; - actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrotFacing"; + actions[VS::SHADER_SPATIAL].renames["FRONT_FACING"] = "gl_FrontFacing"; actions[VS::SHADER_SPATIAL].renames["NORMALMAP"] = "normalmap"; actions[VS::SHADER_SPATIAL].renames["NORMALMAP_DEPTH"] = "normaldepth"; actions[VS::SHADER_SPATIAL].renames["ALBEDO"] = "albedo"; @@ -751,9 +783,11 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss"; actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy"; actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow"; - actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"] = "sss_spread"; + //actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"] = "sss_spread"; actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength"; + actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission"; actions[VS::SHADER_SPATIAL].renames["AO"] = "ao"; + actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect"; actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission"; //actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2; actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord"; @@ -764,6 +798,13 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["SIDE"] = "side"; actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; + //for light + actions[VS::SHADER_SPATIAL].renames["VIEW"] = "view"; + actions[VS::SHADER_SPATIAL].renames["LIGHT_COLOR"] = "light_color"; + 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"; + actions[VS::SHADER_SPATIAL].usage_defines["TANGENT"] = "#define ENABLE_TANGENT_INTERP\n"; actions[VS::SHADER_SPATIAL].usage_defines["BINORMAL"] = "@TANGENT"; actions[VS::SHADER_SPATIAL].usage_defines["RIM"] = "#define LIGHT_USE_RIM\n"; @@ -773,6 +814,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY"] = "#define LIGHT_USE_ANISOTROPY\n"; actions[VS::SHADER_SPATIAL].usage_defines["ANISOTROPY_FLOW"] = "@ANISOTROPY"; actions[VS::SHADER_SPATIAL].usage_defines["AO"] = "#define ENABLE_AO\n"; + actions[VS::SHADER_SPATIAL].usage_defines["AO_LIGHT_AFFECT"] = "#define ENABLE_AO\n"; actions[VS::SHADER_SPATIAL].usage_defines["UV"] = "#define ENABLE_UV_INTERP\n"; actions[VS::SHADER_SPATIAL].usage_defines["UV2"] = "#define ENABLE_UV2_INTERP\n"; actions[VS::SHADER_SPATIAL].usage_defines["NORMALMAP"] = "#define ENABLE_NORMALMAP\n"; @@ -782,6 +824,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].usage_defines["ALPHA_SCISSOR"] = "#define ALPHA_SCISSOR_USED\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["SCREEN_UV"] = "#define SCREEN_UV_USED\n"; @@ -792,9 +835,10 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_burley"] = "#define DIFFUSE_BURLEY\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_oren_nayar"] = "#define DIFFUSE_OREN_NAYAR\n"; - actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_half_lambert"] = "#define DIFFUSE_HALF_LAMBERT\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_lambert_wrap"] = "#define DIFFUSE_LAMBERT_WRAP\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["diffuse_toon"] = "#define DIFFUSE_TOON\n"; + actions[VS::SHADER_SPATIAL].render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_blinn"] = "#define SPECULAR_BLINN\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_phong"] = "#define SPECULAR_PHONG\n"; actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n"; diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index f0dc14c35a..731d6968ce 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -105,20 +105,26 @@ VERTEX_SHADER_GLOBALS void main() { - vec4 vertex_color = color_attrib; + vec4 color = color_attrib; #ifdef USE_INSTANCING mat4 extra_matrix2 = extra_matrix * transpose(mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0))); - vertex_color*=instance_color; + color*=instance_color; + vec4 instance_custom = instance_custom_data; + #else mat4 extra_matrix2 = extra_matrix; + vec4 instance_custom = vec4(0.0); #endif #ifdef USE_TEXTURE_RECT - - uv_interp = src_rect.xy + abs(src_rect.zw) * vertex; - highp vec4 outvec = vec4(dst_rect.xy + dst_rect.zw * mix(vertex,vec2(1.0,1.0)-vertex,lessThan(src_rect.zw,vec2(0.0,0.0))),0.0,1.0); + 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; + } else { + uv_interp = src_rect.xy + abs(src_rect.zw) * vertex; + } + highp vec4 outvec = vec4(dst_rect.xy + abs(dst_rect.zw) * mix(vertex,vec2(1.0,1.0)-vertex,lessThan(src_rect.zw,vec2(0.0,0.0))),0.0,1.0); #else uv_interp = uv_attrib; @@ -132,18 +138,17 @@ void main() { //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_data.z),total_frames-1); + 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 / v_frames); + uv_interp.y = uv_interp.y * frame_h + frame_h * float(frame / h_frames); #endif #define extra_matrix extra_matrix2 { - vec2 src_vtx=outvec.xy; VERTEX_SHADER_CODE @@ -162,7 +167,7 @@ VERTEX_SHADER_CODE #undef extra_matrix - color_interp = vertex_color; + color_interp = color; #ifdef USE_PIXEL_SNAP @@ -572,6 +577,18 @@ FRAGMENT_SHADER_CODE #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); @@ -579,7 +596,7 @@ FRAGMENT_SHADER_CODE SHADOW_TEST(su-shadowpixel_size); SHADOW_TEST(su-shadowpixel_size*2.0); SHADOW_TEST(su-shadowpixel_size*3.0); - shadow_attenuation/=5.0; + shadow_attenuation/=7.0; #endif @@ -635,4 +652,3 @@ FRAGMENT_SHADER_CODE frag_color = color; } - diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl index d33193ee50..743fe122d1 100644 --- a/drivers/gles3/shaders/copy.glsl +++ b/drivers/gles3/shaders/copy.glsl @@ -27,6 +27,8 @@ void main() { #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) cube_interp = cube_in; +#elif defined(USE_ASYM_PANO) + uv_interp = vertex_attrib.xy; #else uv_interp = uv_in; #ifdef V_FLIP @@ -59,6 +61,11 @@ in vec3 cube_interp; in vec2 uv_interp; #endif +#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 @@ -70,7 +77,7 @@ uniform sampler2D source; //texunit:0 uniform float multiplier; #endif -#ifdef USE_PANORAMA +#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO) vec4 texturePanorama(vec3 normal,sampler2D pano ) { @@ -122,6 +129,21 @@ void main() { vec4 color = texturePanorama( normalize(cube_interp), source ); +#elif defined(USE_ASYM_PANO) + + // When an assymetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. + // Note that we're ignoring the x-offset for IPD, with Z sufficiently in the distance it becomes neglectible, as a result we could probably just set cube_normal.z to -1. + // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. + + vec3 cube_normal; + cube_normal.z = -1000000.0; + cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; + cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; + cube_normal = mat3(pano_transform) * cube_normal; + cube_normal.z = -cube_normal.z; + + vec4 color = texturePanorama( normalize(cube_normal.xyz), source ); + #elif defined(USE_CUBEMAP) vec4 color = texture( source_cube, normalize(cube_interp) ); diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index 09e522866c..b5f98a1244 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -168,7 +168,11 @@ void main() { float depth = textureLod( 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; +#else depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); +#endif float amount = smoothstep(dof_begin,dof_end,depth); float k_accum=0.0; @@ -182,8 +186,11 @@ void main() { float tap_depth = texture( 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); tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect @@ -221,7 +228,11 @@ void main() { float tap_depth = texture( 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 = 1.0-smoothstep(dof_end,dof_begin,tap_depth); tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index ef4925895c..9880663143 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -1,5 +1,6 @@ [vertex] +#define M_PI 3.14159265359 /* from VisualServer: @@ -61,6 +62,7 @@ layout(location=12) in highp vec4 instance_custom_data; layout(std140) uniform SceneData { //ubo:0 highp mat4 projection_matrix; + highp mat4 inv_projection_matrix; highp mat4 camera_inverse_matrix; highp mat4 camera_matrix; @@ -78,6 +80,7 @@ layout(std140) uniform SceneData { //ubo:0 highp float shadow_dual_paraboloid_render_zfar; highp float shadow_dual_paraboloid_render_side; + highp vec2 viewport_size; highp vec2 screen_pixel_size; highp vec2 shadow_atlas_pixel_size; highp vec2 directional_shadow_pixel_size; @@ -162,10 +165,10 @@ uniform int spot_light_count; out vec4 diffuse_light_interp; 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) { +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; + diffuse += dotNL * light_color / M_PI; if (roughness > 0.0) { @@ -484,7 +487,7 @@ VERTEX_SHADER_CODE vec3 directional_diffuse = vec3(0.0); vec3 directional_specular = vec3(0.0); - light_compute(normal_interp,-light_direction_attenuation.xyz,-normalize( vertex_interp ),normal_interp,roughness,directional_diffuse,directional_specular); + light_compute(normal_interp,-light_direction_attenuation.xyz,-normalize( vertex_interp ),light_color_energy.rgb,roughness,directional_diffuse,directional_specular); float diff_avg = dot(diffuse_light_interp.rgb,vec3(0.33333)); float diff_dir_avg = dot(directional_diffuse,vec3(0.33333)); @@ -564,6 +567,7 @@ in vec3 normal_interp; uniform bool no_ambient_light; + #ifdef USE_RADIANCE_MAP @@ -588,7 +592,7 @@ vec3 textureDualParaboloid(sampler2DArray p_tex, vec3 p_vec,float p_roughness) { norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25); // we need to lie the derivatives (normg) and assume that DP side is always the same - // to get proper texure filtering + // to get proper texture filtering vec2 normg=norm.xy; if (norm.z>0.0) { norm.y=0.5-norm.y+0.5; @@ -643,6 +647,7 @@ FRAGMENT_SHADER_GLOBALS layout(std140) uniform SceneData { highp mat4 projection_matrix; + highp mat4 inv_projection_matrix; highp mat4 camera_inverse_matrix; highp mat4 camera_matrix; @@ -660,6 +665,7 @@ layout(std140) uniform SceneData { highp float shadow_dual_paraboloid_render_zfar; highp float shadow_dual_paraboloid_render_side; + highp vec2 viewport_size; highp vec2 screen_pixel_size; highp vec2 shadow_atlas_pixel_size; highp vec2 directional_shadow_pixel_size; @@ -862,11 +868,57 @@ float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) { #endif -// GGX Specular -// Source: http://www.filmicworlds.com/images/ggx-opt/optimized-ggx.hlsl -float G1V(float dotNV, float k) -{ - return 1.0 / (dotNV * (1.0 - k) + k); + +// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V. +// We're dividing this factor off because the overall term we'll end up looks like +// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012): +// +// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V) +// +// We're basically regouping this as +// +// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)] +// +// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V. +// +// The contents of the D and G (G1) functions (GGX) are taken from +// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). +// Eqns 71-72 and 85-86 (see also Eqns 43 and 80). + +float G_GGX_2cos(float cos_theta_m, float alpha) { + // Schlick's approximation + // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) + // Eq. (19), although see Heitz (2014) the about the problems with his derivation. + // It nevertheless approximates GGX well with k = alpha/2. + float k = 0.5*alpha; + return 0.5 / (cos_theta_m * (1.0 - k) + k); + + // float cos2 = cos_theta_m*cos_theta_m; + // float sin2 = (1.0-cos2); + // return 1.0 /( cos_theta_m + sqrt(cos2 + alpha*alpha*sin2) ); +} + +float D_GGX(float cos_theta_m, float alpha) { + float alpha2 = alpha*alpha; + float d = 1.0 + (alpha2-1.0)*cos_theta_m*cos_theta_m; + return alpha2/(M_PI * d * d); +} + +float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { + float cos2 = cos_theta_m * cos_theta_m; + float sin2 = (1.0-cos2); + float s_x = alpha_x * cos_phi; + float s_y = alpha_y * sin_phi; + return 1.0 / (cos_theta_m + sqrt(cos2 + (s_x*s_x + s_y*s_y)*sin2 )); +} + +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; + 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 / (M_PI * alpha_x * alpha_y * d * d ); } @@ -885,76 +937,107 @@ 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? +} - -void light_compute(vec3 N, vec3 L,vec3 V,vec3 B, vec3 T,vec3 light_color,vec3 diffuse_color, float specular_blob_intensity, float roughness, float rim,float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,inout vec3 diffuse, inout vec3 specular) { +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) { #if defined(USE_LIGHT_SHADER_CODE) //light is written by the light shader + vec3 normal = N; + vec3 albedo = diffuse_color; + vec3 light = L; + vec3 view = V; LIGHT_SHADER_CODE #else + 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 (metallic < 1.0) { +#if defined(DIFFUSE_OREN_NAYAR) + vec3 diffuse_brdf_NL; +#else + float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance +#endif - float dotNL = max(dot(N,L), 0.0 ); - -#if defined(DIFFUSE_HALF_LAMBERT) - float hl = dot(N,L) * 0.5 + 0.5; - diffuse += hl * light_color * diffuse_color; +#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) - { - float LdotV = dot(L, V); - float NdotL = dot(L, N); - float NdotV = dot(N, V); + { + // 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; - vec3 A = 1.0 + sigma2 * (diffuse_color / (sigma2 + 0.13) + 0.5 / (sigma2 + 0.33)); - float B = 0.45 * sigma2 / (sigma2 + 0.09); + float s = LdotV - NdotL * NdotV; + float t = mix(1.0, max(NdotL, NdotV), step(0.0, s)); - diffuse += diffuse_color * max(0.0, NdotL) * (A + vec3(B) * s / t) / M_PI; - } + float sigma2 = roughness * roughness; // TODO: this needs checking + vec3 A = 1.0 + sigma2 * (- 0.5 / (sigma2 + 0.33) + 0.17*diffuse_color / (sigma2 + 0.13) ); + float B = 0.45 * sigma2 / (sigma2 + 0.09); + + diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI); + } #elif defined(DIFFUSE_TOON) - diffuse += smoothstep(-roughness,max(roughness,0.01),dot(N,L)) * light_color * diffuse_color; + diffuse_brdf_NL = smoothstep(-roughness,max(roughness,0.01),NdotL); #elif defined(DIFFUSE_BURLEY) - { - float NdotL = dot(L, N); - float NdotV = dot(N, V); - float VdotH = dot(N, normalize(L+V)); - float energyBias = mix(roughness, 0.0, 0.5); - float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); - float fd90 = energyBias + 2.0 * VdotH * VdotH * roughness; - float f0 = 1.0; - float lightScatter = f0 + (fd90 - f0) * pow(1.0 - NdotL, 5.0); - float viewScatter = f0 + (fd90 - f0) * pow(1.0 - NdotV, 5.0); - - diffuse+= light_color * diffuse_color * lightScatter * viewScatter * energyFactor; - } + { + + + vec3 H = normalize(V + L); + float cLdotH = max(0.0,dot(L, H)); + + float FD90 = 0.5 + 2.0 * cLdotH * cLdotH * roughness; + float FdV = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotV); + float FdL = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotL); + diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; + /* + float energyBias = mix(roughness, 0.0, 0.5); + float energyFactor = mix(roughness, 1.0, 1.0 / 1.51); + float fd90 = energyBias + 2.0 * VoH * VoH * roughness; + float f0 = 1.0; + float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0); + float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0); + + diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;*/ + } +#else + //lambert + diffuse_brdf_NL = cNdotL * (1.0 / M_PI); +#endif + +#if defined(TRANSMISSION_USED) + diffuse_light += light_color * diffuse_color * mix(vec3(diffuse_brdf_NL), vec3(M_PI), transmission) * attenuation; #else - //lambert - diffuse += dotNL * light_color * diffuse_color; + diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation; #endif - float dotNV = max(dot(N,V), 0.0 ); + #if defined(LIGHT_USE_RIM) - float rim_light = pow(1.0-dotNV,(1.0-roughness)*16.0); - diffuse += rim_light * rim * mix(vec3(1.0),diffuse_color,rim_tint) * light_color; + float rim_light = pow(1.0-cNdotV, (1.0-roughness)*16.0); + diffuse_light += rim_light * rim * mix(vec3(1.0),diffuse_color,rim_tint) * light_color; #endif + } - if (roughness > 0.0) { + if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely // D @@ -962,77 +1045,83 @@ LIGHT_SHADER_CODE #if defined(SPECULAR_BLINN) vec3 H = normalize(V + L); - float dotNH = max(dot(N,H), 0.0 ); - float intensity = pow( dotNH, (1.0-roughness) * 256.0); - specular += light_color * intensity * specular_blob_intensity; + float cNdotH = max(dot(N,H), 0.0 ); + float intensity = pow( cNdotH, (1.0-roughness) * 256.0); + specular_light += light_color * intensity * specular_blob_intensity * attenuation; #elif defined(SPECULAR_PHONG) vec3 R = normalize(-reflect(L,N)); - float dotNV = max(0.0,dot(R,V)); - float intensity = pow( dotNV, (1.0-roughness) * 256.0); - specular += light_color * intensity * specular_blob_intensity; + float cRdotV = max(0.0,dot(R,V)); + float intensity = pow( cRdotV, (1.0-roughness) * 256.0); + specular_light += light_color * intensity * specular_blob_intensity * attenuation; #elif defined(SPECULAR_TOON) vec3 R = normalize(-reflect(L,N)); - float dotNV = dot(R,V); + float RdotV = dot(R,V); float mid = 1.0-roughness; mid*=mid; - float intensity = smoothstep(mid-roughness*0.5,mid+roughness*0.5,dotNV) * mid; - diffuse += light_color * intensity * specular_blob_intensity; //write to diffuse, as in toon shading you generally want no reflection + float intensity = smoothstep(mid-roughness*0.5, mid+roughness*0.5, RdotV) * mid; + diffuse_light += light_color * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection #elif defined(SPECULAR_DISABLED) //none.. -#else +#elif defined(SPECULAR_SCHLICK_GGX) // shlick+ggx as default - float alpha = roughness * roughness; vec3 H = normalize(V + L); - float dotNH = max(dot(N,H), 0.0 ); - float dotLH = max(dot(L,H), 0.0 ); + float cNdotH = max(dot(N,H), 0.0); + float cLdotH = max(dot(L,H), 0.0); -#if defined(LIGHT_USE_ANISOTROPY) +# if defined(LIGHT_USE_ANISOTROPY) 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 dotXH = dot( T, H ); - float dotYH = dot( B, H ); - float pi = M_PI; - float denom = dotXH*dotXH / (ax*ax) + dotYH*dotYH / (ay*ay) + dotNH*dotNH; - float D = 1.0 / ( pi * ax*ay * denom*denom ); + 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 alphaSqr = alpha * alpha; - float pi = M_PI; - float denom = dotNH * dotNH * (alphaSqr - 1.0) + 1.0; - float D = alphaSqr / (pi * denom * denom); -#endif +# else + float alpha = roughness * roughness; + float D = D_GGX(cNdotH, alpha); + float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); +# endif // F - float F0 = 1.0; - float dotLH5 = SchlickFresnel( dotLH ); - float F = F0 + (1.0 - F0) * (dotLH5); - - // V - float k = alpha / 2.0f; - float vis = G1V(dotNL, k) * G1V(dotNV, k); + float F0 = 1.0; // FIXME + float cLdotH5 = SchlickFresnel(cLdotH); + float F = mix(cLdotH5, 1.0, F0); - float speci = dotNL * D * F * vis; + float specular_brdf_NL = cNdotL * D * F * G; - specular += speci * light_color * specular_blob_intensity; + specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #endif #if defined(LIGHT_USE_CLEARCOAT) - float Dr = GTR1(dotNH, mix(.1,.001,clearcoat_gloss)); - float Fr = mix(.04, 1.0, dotLH5); - float Gr = G1V(dotNL, .25) * G1V(dotNV, .25); + if (clearcoat_gloss > 0.0) { +# if !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) + vec3 H = normalize(V + L); +# endif +# if !defined(SPECULAR_SCHLICK_GGX) + float cNdotH = max(dot(N,H), 0.0); + float cLdotH = max(dot(L,H), 0.0); + float cLdotH5 = SchlickFresnel(cLdotH); +#endif + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + - specular += .25*clearcoat*Gr*Fr*Dr; + float specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + + specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; + } #endif } @@ -1060,9 +1149,7 @@ 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)); return avg*(1.0/13.0); -#endif - -#ifdef SHADOW_MODE_PCF_5 +#elif defined(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)); @@ -1070,11 +1157,11 @@ 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)); avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0)); return avg*(1.0/5.0); -#endif -#if !defined(SHADOW_MODE_PCF_5) && !defined(SHADOW_MODE_PCF_13) +#else return textureProj(shadow,vec4(pos,depth,1.0)); + #endif } @@ -1116,7 +1203,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, float roughness, 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 rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex; float light_length = length( light_rel_vec ); @@ -1170,11 +1257,11 @@ void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal,vec3 bino light_attenuation*=mix(omni_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow); } - light_compute(normal,normalize(light_rel_vec),eye_vec,binormal,tangent,omni_lights[idx].light_color_energy.rgb*light_attenuation,albedo,omni_lights[idx].light_params.z*p_blob_intensity,roughness,rim,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,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); } -void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent,vec3 albedo, float roughness, 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 rim, float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz-vertex; float light_length = length( light_rel_vec ); @@ -1204,7 +1291,7 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi light_attenuation*=mix(spot_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow); } - light_compute(normal,normalize(light_rel_vec),eye_vec,binormal,tangent,spot_lights[idx].light_color_energy.rgb*light_attenuation,albedo,spot_lights[idx].light_params.z*p_blob_intensity,roughness,rim,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,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); } @@ -1499,6 +1586,7 @@ void main() { //lay out everything, whathever is unused is optimized away anyway highp vec3 vertex = vertex_interp; vec3 albedo = vec3(0.8,0.8,0.8); + vec3 transmission = vec3(0.0); float metallic = 0.0; float specular = 0.5; vec3 emission = vec3(0.0,0.0,0.0); @@ -1512,6 +1600,7 @@ void main() { #if defined(ENABLE_AO) float ao=1.0; + float ao_light_affect=0.0; #endif float alpha = 1.0; @@ -1577,6 +1666,12 @@ FRAGMENT_SHADER_CODE } #endif +#ifdef USE_OPAQUE_PREPASS + + if (alpha<0.99) { + discard; + } +#endif #if defined(ENABLE_NORMALMAP) @@ -1678,9 +1773,16 @@ FRAGMENT_SHADER_CODE vec3 light_attenuation=vec3(1.0); + float depth_z = -vertex.z; #ifdef LIGHT_DIRECTIONAL_SHADOW - if (gl_FragCoord.w > shadow_split_offsets.w) { +#ifdef LIGHT_USE_PSSM4 + if (depth_z < shadow_split_offsets.w) { +#elif defined(LIGHT_USE_PSSM2) + if (depth_z < shadow_split_offsets.y) { +#else + if (depth_z < shadow_split_offsets.x) { +#endif //LIGHT_USE_PSSM4 vec3 pssm_coord; float pssm_fade=0.0; @@ -1689,17 +1791,15 @@ FRAGMENT_SHADER_CODE float pssm_blend; vec3 pssm_coord2; bool use_blend=true; - vec3 light_pssm_split_inv = 1.0/shadow_split_offsets.xyz; - float w_inv = 1.0/gl_FragCoord.w; #endif #ifdef LIGHT_USE_PSSM4 - if (gl_FragCoord.w > shadow_split_offsets.y) { + if (depth_z < shadow_split_offsets.y) { - if (gl_FragCoord.w > shadow_split_offsets.x) { + if (depth_z < shadow_split_offsets.x) { highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); pssm_coord=splane.xyz/splane.w; @@ -1709,7 +1809,7 @@ FRAGMENT_SHADER_CODE splane=(shadow_matrix2 * vec4(vertex,1.0)); pssm_coord2=splane.xyz/splane.w; - pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); + pssm_blend=smoothstep(0.0,shadow_split_offsets.x,depth_z); #endif } else { @@ -1720,14 +1820,14 @@ FRAGMENT_SHADER_CODE #if defined(LIGHT_USE_PSSM_BLEND) splane=(shadow_matrix3 * vec4(vertex,1.0)); pssm_coord2=splane.xyz/splane.w; - pssm_blend=smoothstep(light_pssm_split_inv.x,light_pssm_split_inv.y,w_inv); + pssm_blend=smoothstep(shadow_split_offsets.x,shadow_split_offsets.y,depth_z); #endif } } else { - if (gl_FragCoord.w > shadow_split_offsets.z) { + if (depth_z < shadow_split_offsets.z) { highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0)); pssm_coord=splane.xyz/splane.w; @@ -1735,13 +1835,14 @@ FRAGMENT_SHADER_CODE #if defined(LIGHT_USE_PSSM_BLEND) splane=(shadow_matrix4 * vec4(vertex,1.0)); pssm_coord2=splane.xyz/splane.w; - pssm_blend=smoothstep(light_pssm_split_inv.y,light_pssm_split_inv.z,w_inv); + pssm_blend=smoothstep(shadow_split_offsets.y,shadow_split_offsets.z,depth_z); #endif } else { + highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0)); pssm_coord=splane.xyz/splane.w; - pssm_fade = smoothstep(shadow_split_offsets.z,shadow_split_offsets.w,gl_FragCoord.w); + pssm_fade = smoothstep(shadow_split_offsets.z,shadow_split_offsets.w,depth_z); #if defined(LIGHT_USE_PSSM_BLEND) use_blend=false; @@ -1757,7 +1858,7 @@ FRAGMENT_SHADER_CODE #ifdef LIGHT_USE_PSSM2 - if (gl_FragCoord.w > shadow_split_offsets.x) { + if (depth_z < shadow_split_offsets.x) { highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0)); pssm_coord=splane.xyz/splane.w; @@ -1767,13 +1868,13 @@ FRAGMENT_SHADER_CODE splane=(shadow_matrix2 * vec4(vertex,1.0)); pssm_coord2=splane.xyz/splane.w; - pssm_blend=smoothstep(0.0,light_pssm_split_inv.x,w_inv); + pssm_blend=smoothstep(0.0,shadow_split_offsets.x,depth_z); #endif } else { highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0)); pssm_coord=splane.xyz/splane.w; - pssm_fade = smoothstep(shadow_split_offsets.x,shadow_split_offsets.y,gl_FragCoord.w); + pssm_fade = smoothstep(shadow_split_offsets.x,shadow_split_offsets.y,depth_z); #if defined(LIGHT_USE_PSSM_BLEND) use_blend=false; @@ -1815,6 +1916,7 @@ FRAGMENT_SHADER_CODE } + #endif //LIGHT_DIRECTIONAL_SHADOW #ifdef USE_VERTEX_LIGHTING @@ -1822,7 +1924,7 @@ FRAGMENT_SHADER_CODE specular_light*=mix(vec3(1.0),light_attenuation,specular_light_interp.a); #else - light_compute(normal,-light_direction_attenuation.xyz,eye_vec,binormal,tangent,light_color_energy.rgb*light_attenuation,albedo,light_params.z*specular_blob_intensity,roughness,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,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light); #endif @@ -1860,11 +1962,11 @@ FRAGMENT_SHADER_CODE #else for(int i=0;i<omni_light_count;i++) { - light_process_omni(omni_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,roughness,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,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,specular_blob_intensity,diffuse_light,specular_light); } for(int i=0;i<spot_light_count;i++) { - light_process_spot(spot_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,roughness,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,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,specular_blob_intensity,diffuse_light,specular_light); } #endif //USE_VERTEX_LIGHTING @@ -1883,12 +1985,16 @@ FRAGMENT_SHADER_CODE #if defined(ENABLE_AO) ambient_light*=ao; + ao_light_affect = mix(1.0,ao,ao_light_affect); + specular_light*=ao_light_affect; + diffuse_light*=ao_light_affect; #endif - //energu conservation - diffuse_light=mix(diffuse_light,vec3(0.0),metallic); - ambient_light=mix(ambient_light,vec3(0.0),metallic); + + //energy conservation + 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; { @@ -1897,18 +2003,17 @@ FRAGMENT_SHADER_CODE //simplify for toon, as specular_light *= specular * metallic * albedo * 2.0; #else - //brdf approximation (Lazarov 2013) - float ndotv = clamp(dot(normal,eye_vec),0.0,1.0); - vec3 dielectric = vec3(0.034) * specular * 2.0; - //energy conservation - vec3 f0 = mix(dielectric, albedo, metallic); + // 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 brdf = vec2( -1.04, 1.04 ) * a004 + r.zw; + vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw; - specular_light *= min(1.0,50.0 * f0.g) * brdf.y + brdf.x * f0; + vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo); + specular_light *= AB.x * specular_color + AB.y; #endif } @@ -2007,5 +2112,3 @@ FRAGMENT_SHADER_CODE } - - diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl index cc41d36c37..b2e6f7a736 100644 --- a/drivers/gles3/shaders/screen_space_reflection.glsl +++ b/drivers/gles3/shaders/screen_space_reflection.glsl @@ -56,7 +56,6 @@ vec2 view_to_screen(vec3 view_pos,out float w) { #define M_PI 3.14159265359 - void main() { @@ -158,8 +157,13 @@ void main() { w+=w_advance; //convert to linear depth + depth = texture(source_depth, pos*pixel_size).r * 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; +#else depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); +#endif depth=-depth; z_from = z_to; diff --git a/drivers/gles3/shaders/ssao.glsl b/drivers/gles3/shaders/ssao.glsl index 0e8fc89d6c..219f0957e0 100644 --- a/drivers/gles3/shaders/ssao.glsl +++ b/drivers/gles3/shaders/ssao.glsl @@ -13,8 +13,24 @@ void main() { #define TWO_PI 6.283185307179586476925286766559 +#ifdef SSAO_QUALITY_HIGH + +#define NUM_SAMPLES (80) + +#endif + +#ifdef SSAO_QUALITY_LOW + #define NUM_SAMPLES (15) +#endif + +#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH) + +#define NUM_SAMPLES (40) + +#endif + // If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower // miplevel to maintain reasonable spatial locality in the cache // If this number is too small (< 3), too many taps will land in the same pixel, and we'll get bad variance that manifests as flashing. @@ -65,7 +81,12 @@ layout(location = 0) out float visibility; uniform vec4 proj_info; vec3 reconstructCSPosition(vec2 S, float z) { - return vec3((S.xy * proj_info.xy + proj_info.zw) * z, z); +#ifdef USE_ORTHOGONAL_PROJECTION + return vec3((S.xy * proj_info.xy + proj_info.zw), z); +#else + return vec3((S.xy * proj_info.xy + proj_info.zw) * z, z); + +#endif } vec3 getPosition(ivec2 ssP) { @@ -73,7 +94,11 @@ vec3 getPosition(ivec2 ssP) { P.z = texelFetch(source_depth, ssP, 0).r; P.z = P.z * 2.0 - 1.0; +#ifdef USE_ORTHOGONAL_PROJECTION + P.z = ((P.z + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0; +#else P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near)); +#endif P.z = -P.z; // Offset to pixel center @@ -118,7 +143,12 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) { //read from depth buffer P.z = texelFetch(source_depth, mipP, 0).r; P.z = P.z * 2.0 - 1.0; +#ifdef USE_ORTHOGONAL_PROJECTION + P.z = ((P.z + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0; +#else P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near)); + +#endif P.z = -P.z; } else { @@ -198,12 +228,12 @@ void main() { //visibility=-C.z/camera_z_far; //return; - - //vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0; - +#if 0 + vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0; +#else vec3 n_C = reconstructCSFaceNormal(C); n_C = -n_C; - +#endif // Hash function used in the HPG12 AlchemyAO paper float randomPatternRotationAngle = mod(float((3 * ssC.x ^ ssC.y + ssC.x * ssC.y) * 10), TWO_PI); @@ -214,8 +244,11 @@ void main() { // Choose the screen-space sample radius // proportional to the projected area of the sphere +#ifdef USE_ORTHOGONAL_PROJECTION + float ssDiskRadius = -proj_scale * radius; +#else float ssDiskRadius = -proj_scale * radius / C.z; - +#endif float sum = 0.0; for (int i = 0; i < NUM_SAMPLES; ++i) { sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius,i, randomPatternRotationAngle); diff --git a/drivers/gles3/shaders/ssao_blur.glsl b/drivers/gles3/shaders/ssao_blur.glsl index c7c978dc37..472dc21acf 100644 --- a/drivers/gles3/shaders/ssao_blur.glsl +++ b/drivers/gles3/shaders/ssao_blur.glsl @@ -15,6 +15,7 @@ void main() { uniform sampler2D source_ssao; //texunit:0 uniform sampler2D source_depth; //texunit:1 +uniform sampler2D source_normal; //texunit:3 layout(location = 0) out float visibility; @@ -24,7 +25,7 @@ layout(location = 0) out float visibility; // Tunable Parameters: /** Increase to make depth edges crisper. Decrease to reduce flicker. */ -#define EDGE_SHARPNESS (4.0) +uniform float edge_sharpness; /** Step in 2-pixel intervals since we already blurred against neighbors in the first AO pass. This constant can be increased while R decreases to improve @@ -34,7 +35,8 @@ layout(location = 0) out float visibility; unobjectionable after shading was applied but eliminated most temporal incoherence from using small numbers of sample taps. */ -#define SCALE (3) + +uniform int filter_scale; /** Filter radius in pixels. This will be multiplied by SCALE. */ #define R (4) @@ -63,13 +65,14 @@ void main() { ivec2 ssC = ivec2(gl_FragCoord.xy); float depth = texelFetch(source_depth, ssC, 0).r; + //vec3 normal = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0; depth = depth * 2.0 - 1.0; depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); float depth_divide = 1.0 / camera_z_far; - depth*=depth_divide; +// depth*=depth_divide; /* if (depth > camera_z_far*0.999) { @@ -92,20 +95,23 @@ void main() { // so the IF statement has no runtime cost if (r != 0) { - ivec2 ppos = ssC + axis * (r * SCALE); + ivec2 ppos = ssC + axis * (r * filter_scale); float value = texelFetch(source_ssao, clamp(ppos,ivec2(0),clamp_limit), 0).r; - float temp_depth = texelFetch(source_depth, clamp(ssC,ivec2(0),clamp_limit), 0).r; + ivec2 rpos = clamp(ppos,ivec2(0),clamp_limit); + float temp_depth = texelFetch(source_depth, rpos, 0).r; + //vec3 temp_normal = texelFetch(source_normal, rpos, 0).rgb * 2.0 - 1.0; temp_depth = temp_depth * 2.0 - 1.0; temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near)); - temp_depth *= depth_divide; +// temp_depth *= depth_divide; // spatial domain: offset gaussian tap float weight = 0.3 + gaussian[abs(r)]; + //weight *= max(0.0,dot(temp_normal,normal)); // range domain (the "bilateral" weight). As depth difference increases, decrease weight. weight *= max(0.0, 1.0 - - (EDGE_SHARPNESS * 2000.0) * abs(temp_depth - depth) + - edge_sharpness * abs(temp_depth - depth) ); sum += value * weight; diff --git a/drivers/gles3/shaders/ssao_minify.glsl b/drivers/gles3/shaders/ssao_minify.glsl index 6e46a1842c..647c762438 100644 --- a/drivers/gles3/shaders/ssao_minify.glsl +++ b/drivers/gles3/shaders/ssao_minify.glsl @@ -41,7 +41,11 @@ void main() { #ifdef MINIFY_START float fdepth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r; fdepth = fdepth * 2.0 - 1.0; +#ifdef USE_ORTHOGONAL_PROJECTION + fdepth = ((fdepth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0; +#else fdepth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - fdepth * (camera_z_far - camera_z_near)); +#endif fdepth /= camera_z_far; depth = uint(clamp(fdepth*65535.0,0.0,65535.0)); diff --git a/drivers/gles3/shaders/subsurf_scattering.glsl b/drivers/gles3/shaders/subsurf_scattering.glsl index 8873443727..fc66d66198 100644 --- a/drivers/gles3/shaders/subsurf_scattering.glsl +++ b/drivers/gles3/shaders/subsurf_scattering.glsl @@ -17,36 +17,36 @@ void main() { //#define QUALIFIER uniform // some guy on the interweb says it may be faster with this #define QUALIFIER const + #ifdef USE_25_SAMPLES const int kernel_size=25; - QUALIFIER vec2 kernel[25] = vec2[] ( -vec2(0.099654,0.0), -vec2(0.001133,-3.0), -vec2(0.002316,-2.52083), -vec2(0.00445,-2.08333), -vec2(0.008033,-1.6875), -vec2(0.013627,-1.33333), -vec2(0.021724,-1.02083), -vec2(0.032542,-0.75), -vec2(0.04581,-0.520833), -vec2(0.0606,-0.333333), -vec2(0.075333,-0.1875), -vec2(0.088001,-0.0833333), -vec2(0.096603,-0.0208333), -vec2(0.096603,0.0208333), -vec2(0.088001,0.0833333), -vec2(0.075333,0.1875), -vec2(0.0606,0.333333), -vec2(0.04581,0.520833), -vec2(0.032542,0.75), -vec2(0.021724,1.02083), -vec2(0.013627,1.33333), -vec2(0.008033,1.6875), -vec2(0.00445,2.08333), -vec2(0.002316,2.52), -vec2(0.001133,3.0) + vec2(0.530605, 0.0), + vec2(0.000973794, -3.0), + vec2(0.00333804, -2.52083), + vec2(0.00500364, -2.08333), + vec2(0.00700976, -1.6875), + vec2(0.0094389, -1.33333), + vec2(0.0128496, -1.02083), + vec2(0.017924, -0.75), + vec2(0.0263642, -0.520833), + vec2(0.0410172, -0.333333), + vec2(0.0493588, -0.1875), + vec2(0.0402784, -0.0833333), + vec2(0.0211412, -0.0208333), + vec2(0.0211412, 0.0208333), + vec2(0.0402784, 0.0833333), + vec2(0.0493588, 0.1875), + vec2(0.0410172, 0.333333), + vec2(0.0263642, 0.520833), + vec2(0.017924, 0.75), + vec2(0.0128496, 1.02083), + vec2(0.0094389, 1.33333), + vec2(0.00700976, 1.6875), + vec2(0.00500364, 2.08333), + vec2(0.00333804, 2.52083), + vec2(0.000973794, 3.0) ); #endif //USE_25_SAMPLES @@ -56,23 +56,23 @@ vec2(0.001133,3.0) const int kernel_size=17; QUALIFIER vec2 kernel[17] = vec2[]( -vec2(0.197417,0.0), -vec2(0.000078,-2.0), -vec2(0.000489,-1.53125), -vec2(0.002403,-1.125), -vec2(0.009245,-0.78125), -vec2(0.027835,-0.5), -vec2(0.065592,-0.28125), -vec2(0.12098,-0.125), -vec2(0.17467,-0.03125), -vec2(0.17467,0.03125), -vec2(0.12098,0.125), -vec2(0.065592,0.28125), -vec2(0.027835,0.5), -vec2(0.009245,0.78125), -vec2(0.002403,1.125), -vec2(0.000489,1.53125), -vec2(0.000078,2.0) + vec2(0.536343, 0.0), + vec2(0.00317394, -2.0), + vec2(0.0100386, -1.53125), + vec2(0.0144609, -1.125), + vec2(0.0216301, -0.78125), + vec2(0.0347317, -0.5), + vec2(0.0571056, -0.28125), + vec2(0.0582416, -0.125), + vec2(0.0324462, -0.03125), + vec2(0.0324462, 0.03125), + vec2(0.0582416, 0.125), + vec2(0.0571056, 0.28125), + vec2(0.0347317, 0.5), + vec2(0.0216301, 0.78125), + vec2(0.0144609, 1.125), + vec2(0.0100386, 1.53125), + vec2(0.00317394,2.0) ); #endif //USE_17_SAMPLES @@ -82,23 +82,24 @@ vec2(0.000078,2.0) const int kernel_size=11; -QUALIFIER vec2 kernel[kernel_size] = vec2[]( -vec2(0.198596,0.0), -vec2(0.0093,-2.0), -vec2(0.028002,-1.28), -vec2(0.065984,-0.72), -vec2(0.121703,-0.32), -vec2(0.175713,-0.08), -vec2(0.175713,0.08), -vec2(0.121703,0.32), -vec2(0.065984,0.72), -vec2(0.028002,1.28), -vec2(0.0093,2.0) +QUALIFIER vec2 kernel[11] = vec2[]( + vec2(0.560479, 0.0), + vec2(0.00471691, -2.0), + vec2(0.0192831, -1.28), + vec2(0.03639, -0.72), + vec2(0.0821904, -0.32), + vec2(0.0771802, -0.08), + vec2(0.0771802, 0.08), + vec2(0.0821904, 0.32), + vec2(0.03639, 0.72), + vec2(0.0192831, 1.28), + vec2(0.00471691,2.0) ); #endif //USE_11_SAMPLES + uniform float max_radius; uniform float camera_z_far; uniform float camera_z_near; @@ -126,12 +127,16 @@ void main() { // Fetch linear depth of current pixel: float depth = texture(source_depth, uv_interp).r * 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; + float scale = unit_size; //remember depth is negative by default in OpenGL +#else depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near)); + float scale = unit_size / depth; //remember depth is negative by default in OpenGL +#endif - float scale = unit_size / depth; //remember depth is negative by default in OpenGL - // Calculate the final step to fetch the surrounding pixels: vec2 step = max_radius * scale * dir; step *= strength; // Modulate it using the alpha channel. @@ -153,9 +158,14 @@ void main() { #ifdef ENABLE_FOLLOW_SURFACE // If the difference in depth is huge, we lerp color back to "colorM": float depth_cmp = texture(source_depth, offset).r *2.0 - 1.0; + +#ifdef USE_ORTHOGONAL_PROJECTION + depth_cmp = ((depth_cmp + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0; +#else depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near)); +#endif - float s = clamp(300.0f * distance * + float s = clamp(300.0f * scale * max_radius * abs(depth - depth_cmp),0.0,1.0); color = mix(color, base_color.rgb, s); #endif @@ -180,4 +190,3 @@ void main() { frag_color = base_color; } } - diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index 73dec4f90c..2f671158b2 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -175,12 +175,9 @@ vec3 tonemap_reindhart(vec3 color,float white) { return ( color * ( 1.0 + ( color / ( white) ) ) ) / ( 1.0 + color ); } - void main() { - ivec2 coord = ivec2(gl_FragCoord.xy); - vec3 color = texelFetch(source,coord,0).rgb; - + vec4 color = textureLod(source, uv_interp, 0.0); #ifdef USE_AUTO_EXPOSURE @@ -324,5 +321,3 @@ void main() { frag_color=vec4(color.rgb,1.0); } - - diff --git a/drivers/png/SCsub b/drivers/png/SCsub index 6684e36b20..39480351a6 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -5,7 +5,7 @@ Import('env') env_png = env.Clone() # Thirdparty source files -if (env['builtin_libpng'] != 'no'): +if env['builtin_libpng']: thirdparty_dir = "#thirdparty/libpng/" thirdparty_sources = [ "png.c", diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 46c9442ffc..246d4d7650 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -216,8 +216,8 @@ void ImageLoaderPNG::get_recognized_extensions(List<String> *p_extensions) const struct PNGReadStatus { - int offset; - int size; + uint32_t offset; + uint32_t size; const unsigned char *image; }; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 356b1ad958..e4c8641a3b 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -31,34 +31,162 @@ #ifdef PULSEAUDIO_ENABLED -#include <pulse/error.h> +#include <pulse/pulseaudio.h> +#include "os/os.h" #include "project_settings.h" +void pa_state_cb(pa_context *c, void *userdata) { + pa_context_state_t state; + int *pa_ready = (int *)userdata; + + state = pa_context_get_state(c); + switch (state) { + case PA_CONTEXT_FAILED: + case PA_CONTEXT_TERMINATED: + *pa_ready = 2; + break; + + case PA_CONTEXT_READY: + *pa_ready = 1; + break; + } +} + +void sink_info_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) { + unsigned int *channels = (unsigned int *)userdata; + + // If eol is set to a positive number, you're at the end of the list + if (eol > 0) { + return; + } + + *channels = l->channel_map.channels; +} + +void server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) { + char *default_output = (char *)userdata; + + strncpy(default_output, i->default_sink_name, 1024); +} + +static unsigned int detect_channels() { + + pa_mainloop *pa_ml; + pa_mainloop_api *pa_mlapi; + pa_operation *pa_op; + pa_context *pa_ctx; + + int state = 0; + int pa_ready = 0; + + char default_output[1024]; + unsigned int channels = 2; + + pa_ml = pa_mainloop_new(); + pa_mlapi = pa_mainloop_get_api(pa_ml); + pa_ctx = pa_context_new(pa_mlapi, "Godot"); + + int ret = pa_context_connect(pa_ctx, NULL, PA_CONTEXT_NOFLAGS, NULL); + if (ret < 0) { + pa_context_unref(pa_ctx); + pa_mainloop_free(pa_ml); + + return 2; + } + + pa_context_set_state_callback(pa_ctx, pa_state_cb, &pa_ready); + + // Wait until the pa server is ready + while (pa_ready == 0) { + pa_mainloop_iterate(pa_ml, 1, NULL); + } + + // Check if there was an error connecting to the pa server + if (pa_ready == 2) { + pa_context_disconnect(pa_ctx); + pa_context_unref(pa_ctx); + pa_mainloop_free(pa_ml); + + return 2; + } + + // Get the default output device name + pa_op = pa_context_get_server_info(pa_ctx, &server_info_cb, (void *)default_output); + if (pa_op) { + while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) { + ret = pa_mainloop_iterate(pa_ml, 1, NULL); + if (ret < 0) { + ERR_PRINT("pa_mainloop_iterate error"); + } + } + + pa_operation_unref(pa_op); + + // Now using the device name get the amount of channels + pa_op = pa_context_get_sink_info_by_name(pa_ctx, default_output, &sink_info_cb, (void *)&channels); + if (pa_op) { + while (pa_operation_get_state(pa_op) == PA_OPERATION_RUNNING) { + ret = pa_mainloop_iterate(pa_ml, 1, NULL); + if (ret < 0) { + ERR_PRINT("pa_mainloop_iterate error"); + } + } + + pa_operation_unref(pa_op); + } else { + ERR_PRINT("pa_context_get_sink_info_by_name error"); + } + } else { + ERR_PRINT("pa_context_get_server_info error"); + } + + pa_context_disconnect(pa_ctx); + pa_context_unref(pa_ctx); + pa_mainloop_free(pa_ml); + + return channels; +} + Error AudioDriverPulseAudio::init() { active = false; thread_exited = false; exit_thread = false; - pcm_open = false; - samples_in = NULL; - samples_out = NULL; - mix_rate = GLOBAL_DEF("audio/mix_rate", 44100); - speaker_mode = SPEAKER_MODE_STEREO; - channels = 2; + mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE); + channels = detect_channels(); + + switch (channels) { + case 2: // Stereo + case 4: // Surround 3.1 + case 6: // Surround 5.1 + case 8: // Surround 7.1 + break; + + default: + ERR_PRINTS("PulseAudio: Unsupported number of channels: " + itos(channels)); + ERR_FAIL_V(ERR_CANT_OPEN); + break; + } pa_sample_spec spec; spec.format = PA_SAMPLE_S16LE; spec.channels = channels; spec.rate = mix_rate; - int latency = GLOBAL_DEF("audio/output_latency", 25); - buffer_size = closest_power_of_2(latency * mix_rate / 1000); + int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY); + buffer_frames = closest_power_of_2(latency * mix_rate / 1000); + buffer_size = buffer_frames * channels; + + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("PulseAudio: detected " + itos(channels) + " channels"); + print_line("PulseAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); + } pa_buffer_attr attr; - // set to appropriate buffer size from global settings - attr.tlength = buffer_size; + // set to appropriate buffer length (in bytes) from global settings + attr.tlength = buffer_size * sizeof(int16_t); // set them to be automatically chosen attr.prebuf = (uint32_t)-1; attr.maxlength = (uint32_t)-1; @@ -80,8 +208,8 @@ Error AudioDriverPulseAudio::init() { ERR_FAIL_COND_V(pulse == NULL, ERR_CANT_OPEN); } - samples_in = memnew_arr(int32_t, buffer_size * channels); - samples_out = memnew_arr(int16_t, buffer_size * channels); + samples_in.resize(buffer_size); + samples_out.resize(buffer_size); mutex = Mutex::create(); thread = Thread::create(AudioDriverPulseAudio::thread_func, this); @@ -106,18 +234,18 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { while (!ad->exit_thread) { if (!ad->active) { - for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { + for (unsigned int i = 0; i < ad->buffer_size; i++) { ad->samples_out[i] = 0; } } else { ad->lock(); - ad->audio_server_process(ad->buffer_size, ad->samples_in); + ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptr()); ad->unlock(); - for (unsigned int i = 0; i < ad->buffer_size * ad->channels; i++) { + for (unsigned int i = 0; i < ad->buffer_size; i++) { ad->samples_out[i] = ad->samples_in[i] >> 16; } } @@ -125,8 +253,8 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { // pa_simple_write always consumes the entire buffer int error_code; - int byte_size = ad->buffer_size * sizeof(int16_t) * ad->channels; - if (pa_simple_write(ad->pulse, ad->samples_out, byte_size, &error_code) < 0) { + int byte_size = ad->buffer_size * sizeof(int16_t); + if (pa_simple_write(ad->pulse, ad->samples_out.ptr(), byte_size, &error_code) < 0) { // can't recover here fprintf(stderr, "PulseAudio failed and can't recover: %s\n", pa_strerror(error_code)); ad->active = false; @@ -150,7 +278,7 @@ int AudioDriverPulseAudio::get_mix_rate() const { AudioDriver::SpeakerMode AudioDriverPulseAudio::get_speaker_mode() const { - return speaker_mode; + return get_speaker_mode_by_total_channels(channels); } void AudioDriverPulseAudio::lock() { @@ -175,13 +303,10 @@ void AudioDriverPulseAudio::finish() { exit_thread = true; Thread::wait_to_finish(thread); - if (pulse) + if (pulse) { pa_simple_free(pulse); - - if (samples_in) { - memdelete_arr(samples_in); - memdelete_arr(samples_out); - }; + pulse = NULL; + } memdelete(thread); if (mutex) { @@ -197,7 +322,22 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() { mutex = NULL; thread = NULL; pulse = NULL; + + samples_in.clear(); + samples_out.clear(); + + mix_rate = 0; + buffer_size = 0; + channels = 0; + + active = false; + thread_exited = false; + exit_thread = false; + latency = 0; + buffer_frames = 0; + buffer_size = 0; + channels = 0; } AudioDriverPulseAudio::~AudioDriverPulseAudio() { diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index 2f56726617..3ede684496 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -43,24 +43,22 @@ class AudioDriverPulseAudio : public AudioDriver { pa_simple *pulse; - int32_t *samples_in; - int16_t *samples_out; - - static void thread_func(void *p_udata); + Vector<int32_t> samples_in; + Vector<int16_t> samples_out; unsigned int mix_rate; - SpeakerMode speaker_mode; - + unsigned int buffer_frames; unsigned int buffer_size; int channels; bool active; bool thread_exited; mutable bool exit_thread; - bool pcm_open; float latency; + static void thread_func(void *p_udata); + public: const char *get_name() const { return "PulseAudio"; diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp index 7de3ff192e..a184c9e9cf 100644 --- a/drivers/rtaudio/audio_driver_rtaudio.cpp +++ b/drivers/rtaudio/audio_driver_rtaudio.cpp @@ -107,14 +107,13 @@ Error AudioDriverRtAudio::init() { options.numberOfBuffers = 4; parameters.firstChannel = 0; - mix_rate = GLOBAL_DEF("audio/mix_rate", 44100); + mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE); - int latency = GLOBAL_DEF("audio/output_latency", 25); - // calculate desired buffer_size - unsigned int buffer_size = closest_power_of_2(latency * mix_rate / 1000); + int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY); + unsigned int buffer_frames = closest_power_of_2(latency * mix_rate / 1000); if (OS::get_singleton()->is_stdout_verbose()) { - print_line("audio buffer size: " + itos(buffer_size)); + print_line("audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); } short int tries = 2; @@ -127,7 +126,7 @@ Error AudioDriverRtAudio::init() { }; try { - dac->openStream(¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_size, &callback, this, &options); + dac->openStream(¶meters, NULL, RTAUDIO_SINT32, mix_rate, &buffer_frames, &callback, this, &options); active = true; break; @@ -144,7 +143,7 @@ Error AudioDriverRtAudio::init() { } } - return OK; + return active ? OK : ERR_UNAVAILABLE; } int AudioDriverRtAudio::get_mix_rate() const { @@ -199,7 +198,7 @@ AudioDriverRtAudio::AudioDriverRtAudio() { active = false; mutex = NULL; dac = NULL; - mix_rate = 44100; + mix_rate = DEFAULT_MIX_RATE; speaker_mode = SPEAKER_MODE_STEREO; } diff --git a/drivers/unix/SCsub b/drivers/unix/SCsub index 5ced44dfda..c560e1289f 100644 --- a/drivers/unix/SCsub +++ b/drivers/unix/SCsub @@ -14,4 +14,6 @@ f.close() 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 ddc3b2ed33..e7054e11a3 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -35,10 +35,17 @@ #include <sys/statvfs.h> #endif +#include "core/list.h" #include "os/memory.h" #include "print_string.h" #include <errno.h> #include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#ifdef HAVE_MNTENT +#include <mntent.h> +#endif DirAccess *DirAccessUnix::create_fs() { @@ -176,13 +183,96 @@ void DirAccessUnix::list_dir_end() { _cisdir = false; } +#if defined(HAVE_MNTENT) && defined(X11_ENABLED) +static bool _filter_drive(struct mntent *mnt) { + // Ignore devices that don't point to /dev + if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) { + return false; + } + + // Accept devices mounted at common locations + if (strncmp(mnt->mnt_dir, "/media", 6) == 0 || + strncmp(mnt->mnt_dir, "/mnt", 4) == 0 || + strncmp(mnt->mnt_dir, "/home", 5) == 0 || + strncmp(mnt->mnt_dir, "/run/media", 10) == 0) { + return true; + } + + // Ignore everything else + return false; +} +#endif + +static void _get_drives(List<String> *list) { + +#if defined(HAVE_MNTENT) && defined(X11_ENABLED) + // Check /etc/mtab for the list of mounted partitions + FILE *mtab = setmntent("/etc/mtab", "r"); + if (mtab) { + struct mntent mnt; + char strings[4096]; + + while (getmntent_r(mtab, &mnt, strings, sizeof(strings))) { + if (mnt.mnt_dir != NULL && _filter_drive(&mnt)) { + // Avoid duplicates + if (!list->find(mnt.mnt_dir)) { + list->push_back(mnt.mnt_dir); + } + } + } + + endmntent(mtab); + } +#endif + + // Add $HOME + const char *home = getenv("HOME"); + if (home) { + // Only add if it's not a duplicate + if (!list->find(home)) { + list->push_back(home); + } + + // Check $HOME/.config/gtk-3.0/bookmarks + char path[1024]; + snprintf(path, 1024, "%s/.config/gtk-3.0/bookmarks", home); + FILE *fd = fopen(path, "r"); + if (fd) { + char string[1024]; + while (fgets(string, 1024, fd)) { + // Parse only file:// links + if (strncmp(string, "file://", 7) == 0) { + // Strip any unwanted edges on the strings and push_back if it's not a duplicate + String fpath = String(string + 7).strip_edges(); + if (!list->find(fpath)) { + list->push_back(fpath); + } + } + } + + fclose(fd); + } + } + + list->sort(); +} + int DirAccessUnix::get_drive_count() { - return 0; + List<String> list; + _get_drives(&list); + + return list.size(); } + String DirAccessUnix::get_drive(int p_drive) { - return ""; + List<String> list; + _get_drives(&list); + + ERR_FAIL_INDEX_V(p_drive, list.size(), ""); + + return list[p_drive]; } Error DirAccessUnix::make_dir(String p_dir) { @@ -211,36 +301,35 @@ Error DirAccessUnix::make_dir(String p_dir) { Error DirAccessUnix::change_dir(String p_dir) { GLOBAL_LOCK_FUNCTION + p_dir = fix_path(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); - String prev_dir; if (prev_dir.parse_utf8(real_current_dir_name)) prev_dir = real_current_dir_name; //no utf8, maybe latin? - chdir(current_dir.utf8().get_data()); //ascii since this may be unicode or wathever the host os wants - bool worked = (chdir(p_dir.utf8().get_data()) == 0); // we can only give this utf8 - - String base = _get_root_path(); - if (base != "") { - - getcwd(real_current_dir_name, 2048); - String new_dir; - new_dir.parse_utf8(real_current_dir_name); - if (!new_dir.begins_with(base)) - worked = false; + // 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; + next_dir = next_dir.simplify_path(); + try_dir = next_dir; + } else { + try_dir = p_dir; } - if (worked) { - - getcwd(real_current_dir_name, 2048); - if (current_dir.parse_utf8(real_current_dir_name)) - current_dir = real_current_dir_name; //no utf8, maybe latin? + bool worked = (chdir(try_dir.utf8().get_data()) == 0); // we can only give this utf8 + if (!worked) { + return ERR_INVALID_PARAMETER; } + // the directory exists, so set current_dir to try_dir + current_dir = try_dir; chdir(prev_dir.utf8().get_data()); - return worked ? OK : ERR_INVALID_PARAMETER; + return OK; } String DirAccessUnix::get_current_dir() { @@ -307,11 +396,16 @@ size_t DirAccessUnix::get_space_left() { DirAccessUnix::DirAccessUnix() { dir_stream = 0; - current_dir = "."; _cisdir = false; /* determine drive count */ + // set current directory to an absolute path of the current directory + char real_current_dir_name[2048]; + getcwd(real_current_dir_name, 2048); + if (current_dir.parse_utf8(real_current_dir_name)) + current_dir = real_current_dir_name; + change_dir(current_dir); } diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp index d5a66d9a1c..206f57d4a2 100644 --- a/drivers/unix/file_access_unix.cpp +++ b/drivers/unix/file_access_unix.cpp @@ -36,12 +36,17 @@ #include <sys/stat.h> #include <sys/types.h> +#if defined(UNIX_ENABLED) +#include <unistd.h> +#endif + #ifndef ANDROID_ENABLED #include <sys/statvfs.h> #endif #ifdef MSVC #define S_ISREG(m) ((m)&_S_IFREG) +#include <io.h> #endif #ifndef S_ISREG #define S_ISREG(m) ((m)&S_IFREG) @@ -85,13 +90,18 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { //printf("opening %s as %s\n", p_path.utf8().get_data(), path.utf8().get_data()); struct stat st; - if (stat(path.utf8().get_data(), &st) == 0) { - - if (!S_ISREG(st.st_mode)) - return ERR_FILE_CANT_OPEN; - }; + int err = stat(path.utf8().get_data(), &st); + if (!err) { + switch (st.st_mode & S_IFMT) { + case S_IFLNK: + case S_IFREG: + break; + default: + return ERR_FILE_CANT_OPEN; + } + } - if (is_backup_save_enabled() && p_mode_flags & WRITE && !(p_mode_flags & READ)) { + if (is_backup_save_enabled() && (p_mode_flags & WRITE) && !(p_mode_flags & READ)) { save_path = path; path = path + ".tmp"; //print_line("saving instead to "+path); @@ -108,15 +118,19 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) { return OK; } } + void FileAccessUnix::close() { if (!f) return; + fclose(f); f = NULL; + if (close_notification_func) { close_notification_func(path, flags); } + if (save_path != "") { //unlink(save_path.utf8().get_data()); @@ -131,10 +145,12 @@ void FileAccessUnix::close() { ERR_FAIL_COND(rename_error != 0); } } + bool FileAccessUnix::is_open() const { return (f != NULL); } + void FileAccessUnix::seek(size_t p_position) { ERR_FAIL_COND(!f); @@ -143,29 +159,37 @@ void FileAccessUnix::seek(size_t p_position) { if (fseek(f, p_position, SEEK_SET)) check_errors(); } + void FileAccessUnix::seek_end(int64_t p_position) { ERR_FAIL_COND(!f); + if (fseek(f, p_position, SEEK_END)) check_errors(); } -size_t FileAccessUnix::get_pos() const { - size_t aux_position = 0; - if (!(aux_position = ftell(f))) { +size_t FileAccessUnix::get_position() const { + + ERR_FAIL_COND_V(!f, 0); + + int pos = ftell(f); + if (pos < 0) { check_errors(); - }; - return aux_position; + ERR_FAIL_V(0); + } + return pos; } + size_t FileAccessUnix::get_len() const { ERR_FAIL_COND_V(!f, 0); - FileAccessUnix *fau = const_cast<FileAccessUnix *>(this); - int pos = fau->get_pos(); - fau->seek_end(); - int size = fau->get_pos(); - fau->seek(pos); + int pos = ftell(f); + ERR_FAIL_COND_V(pos < 0, 0); + ERR_FAIL_COND_V(fseek(f, 0, SEEK_END), 0); + int size = ftell(f); + ERR_FAIL_COND_V(size < 0, 0); + ERR_FAIL_COND_V(fseek(f, pos, SEEK_SET), 0); return size; } @@ -181,8 +205,8 @@ uint8_t FileAccessUnix::get_8() const { uint8_t b; if (fread(&b, 1, 1, f) == 0) { check_errors(); - }; - + b = '\0'; + } return b; } @@ -199,25 +223,45 @@ Error FileAccessUnix::get_error() const { return last_error; } +void FileAccessUnix::flush() { + + ERR_FAIL_COND(!f); + fflush(f); +} + void FileAccessUnix::store_8(uint8_t p_dest) { ERR_FAIL_COND(!f); - fwrite(&p_dest, 1, 1, f); + ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1); } bool FileAccessUnix::file_exists(const String &p_path) { - FILE *g; - //printf("opening file %s\n", p_fname.c_str()); + int err; + struct stat st; String filename = fix_path(p_path); - g = fopen(filename.utf8().get_data(), "rb"); - if (g == NULL) { + // Does the name exist at all? + err = stat(filename.utf8().get_data(), &st); + if (err) return false; - } else { - fclose(g); - return true; +#ifdef UNIX_ENABLED + // See if we have access to the file + if (access(filename.utf8().get_data(), F_OK)) + return false; +#else + if (_access(filename.utf8().get_data(), 4) == -1) + return false; +#endif + + // See if this is a regular file + switch (st.st_mode & S_IFMT) { + case S_IFLNK: + case S_IFREG: + return true; + default: + return false; } } @@ -225,9 +269,9 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) { String file = fix_path(p_file); struct stat flags; - bool success = (stat(file.utf8().get_data(), &flags) == 0); + int err = stat(file.utf8().get_data(), &flags); - if (success) { + if (!err) { return flags.st_mtime; } else { print_line("ERROR IN: " + p_file); @@ -236,6 +280,15 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) { }; } +Error FileAccessUnix::_chmod(const String &p_path, int p_mod) { + int err = chmod(p_path.utf8().get_data(), p_mod); + if (!err) { + return OK; + } + + return FAILED; +} + FileAccess *FileAccessUnix::create_libc() { return memnew(FileAccessUnix); @@ -249,6 +302,7 @@ FileAccessUnix::FileAccessUnix() { flags = 0; last_error = OK; } + FileAccessUnix::~FileAccessUnix() { close(); diff --git a/drivers/unix/file_access_unix.h b/drivers/unix/file_access_unix.h index 6e5110431f..96f2ff8e26 100644 --- a/drivers/unix/file_access_unix.h +++ b/drivers/unix/file_access_unix.h @@ -62,7 +62,7 @@ public: virtual void seek(size_t p_position); ///< seek to a given position virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - virtual size_t get_pos() const; ///< get position in the file + virtual size_t get_position() const; ///< get position in the file virtual size_t get_len() const; ///< get size of the file virtual bool eof_reached() const; ///< reading passed EOF @@ -72,12 +72,15 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte 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); + FileAccessUnix(); virtual ~FileAccessUnix(); }; diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 75c8a153f6..729abd57ef 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -64,39 +64,7 @@ #include <string.h> #include <sys/time.h> #include <sys/wait.h> - -extern bool _print_error_enabled; - -void OS_Unix::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { - - if (!_print_error_enabled) - return; - - const char *err_details; - if (p_rationale && p_rationale[0]) - err_details = p_rationale; - else - err_details = p_code; - - switch (p_type) { - case ERR_ERROR: - print("\E[1;31mERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;31m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_WARNING: - print("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_SCRIPT: - print("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); - break; - case ERR_SHADER: - print("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); - print("\E[0;36m At: %s:%i.\E[0m\n", p_file, p_line); - break; - } -} +#include <unistd.h> void OS_Unix::debug_break() { @@ -165,29 +133,18 @@ void OS_Unix::initialize_core() { } } -void OS_Unix::finalize_core() { +void OS_Unix::initialize_logger() { + Vector<Logger *> loggers; + loggers.push_back(memnew(UnixTerminalLogger)); + // FIXME: Reenable once we figure out how to get this properly in user:// + // instead of littering the user's working dirs (res:// + pwd) with log files (GH-12277) + //loggers.push_back(memnew(RotatedFileLogger("user://logs/log.txt"))); + _set_logger(memnew(CompositeLogger(loggers))); } -void OS_Unix::vprint(const char *p_format, va_list p_list, bool p_stder) { - - if (p_stder) { - - vfprintf(stderr, p_format, p_list); - fflush(stderr); - } else { - - vprintf(p_format, p_list); - fflush(stdout); - } +void OS_Unix::finalize_core() { } -void OS_Unix::print(const char *p_format, ...) { - - va_list argp; - va_start(argp, p_format); - vprintf(p_format, argp); - va_end(argp); -} void OS_Unix::alert(const String &p_alert, const String &p_title) { fprintf(stderr, "ERROR: %s\n", p_alert.utf8().get_data()); @@ -330,7 +287,7 @@ uint64_t OS_Unix::get_ticks_usec() const { 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) { +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) { if (p_blocking && r_pipe) { @@ -342,7 +299,11 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo argss += String(" \"") + p_arguments[i] + "\""; } - argss += " 2>/dev/null"; //silence stderr + if (read_stderr) { + argss += " 2>&1"; // Read stderr too + } else { + argss += " 2>/dev/null"; //silence stderr + } FILE *f = popen(argss.utf8().get_data(), "r"); ERR_FAIL_COND_V(!f, ERR_CANT_OPEN); @@ -384,7 +345,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo execvp(getprogname(), &args[0]); } #else - execv(p_path.utf8().get_data(), &args[0]); + execvp(p_path.utf8().get_data(), &args[0]); #endif // still alive? something failed.. fprintf(stderr, "**ERROR** OS_Unix::execute - Could not create child process while executing: %s\n", p_path.utf8().get_data()); @@ -559,4 +520,38 @@ String OS_Unix::get_executable_path() const { #endif } +void UnixTerminalLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { + if (!should_log(true)) { + return; + } + + const char *err_details; + if (p_rationale && p_rationale[0]) + err_details = p_rationale; + else + err_details = p_code; + + switch (p_type) { + case ERR_WARNING: + logf_error("\E[1;33mWARNING: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;33m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_SCRIPT: + logf_error("\E[1;35mSCRIPT ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;35m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_SHADER: + logf_error("\E[1;36mSHADER ERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;36m At: %s:%i.\E[0m\n", p_file, p_line); + break; + case ERR_ERROR: + default: + logf_error("\E[1;31mERROR: %s: \E[0m\E[1m%s\n", p_function, err_details); + logf_error("\E[0;31m At: %s:%i.\E[0m\n", p_file, p_line); + break; + } +} + +UnixTerminalLogger::~UnixTerminalLogger() {} + #endif diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index 19e79728fb..87e73534c4 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -54,11 +54,11 @@ protected: virtual int get_audio_driver_count() const; virtual const char *get_audio_driver_name(int p_driver) const; + virtual void initialize_logger(); virtual void initialize_core(); virtual int unix_initialize_audio(int p_audio_driver); //virtual void initialize(int p_video_driver,int p_audio_driver); - //virtual void finalize(); virtual void finalize_core(); String stdin_buf; @@ -66,10 +66,6 @@ protected: String get_global_settings_path() const; public: - 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 = ERR_ERROR); - - virtual void print(const char *p_format, ...); - virtual void vprint(const char *p_format, va_list p_list, bool p_stder = false); virtual void alert(const String &p_alert, const String &p_title = "ALERT!"); virtual String get_stdin_string(bool p_block); @@ -101,7 +97,7 @@ public: 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); + 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 kill(const ProcessID &p_pid); virtual int get_process_id() const; @@ -120,6 +116,12 @@ public: //virtual void run( MainLoop * p_main_loop ); }; +class UnixTerminalLogger : public StdLogger { +public: + virtual void log_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type = ERR_ERROR); + virtual ~UnixTerminalLogger(); +}; + #endif #endif diff --git a/drivers/unix/packet_peer_udp_posix.cpp b/drivers/unix/packet_peer_udp_posix.cpp index b743990b92..61d2737555 100644 --- a/drivers/unix/packet_peer_udp_posix.cpp +++ b/drivers/unix/packet_peer_udp_posix.cpp @@ -73,8 +73,8 @@ Error PacketPeerUDPPosix::get_packet(const uint8_t **r_buffer, int &r_buffer_siz if (queue_count == 0) return ERR_UNAVAILABLE; - uint32_t size; - uint8_t type; + uint32_t size = 0; + uint8_t type = IP::TYPE_NONE; rb.read(&type, 1, true); if (type == IP::TYPE_IPV4) { uint8_t ip[4]; diff --git a/drivers/unix/socket_helpers.h b/drivers/unix/socket_helpers.h index 3fc0144294..0995e5236f 100644 --- a/drivers/unix/socket_helpers.h +++ b/drivers/unix/socket_helpers.h @@ -64,7 +64,6 @@ static size_t _set_sockaddr(struct sockaddr_storage *p_addr, const IP_Address &p // IPv4 socket with IPv6 address ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0); - uint32_t ipv4 = *((uint32_t *)p_ip.get_ipv4()); struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; addr4->sin_family = AF_INET; addr4->sin_port = htons(p_port); // short, network byte order diff --git a/drivers/unix/syslog_logger.cpp b/drivers/unix/syslog_logger.cpp new file mode 100644 index 0000000000..d57f391325 --- /dev/null +++ b/drivers/unix/syslog_logger.cpp @@ -0,0 +1,71 @@ +/*************************************************************************/ +/* syslog_logger.cpp */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 Godot Engine contributors (cf. AUTHORS.md) */ +/* */ +/* Permission is hereby granted, free of charge, to any person obtaining */ +/* a copy of this software and associated documentation files (the */ +/* "Software"), to deal in the Software without restriction, including */ +/* without limitation the rights to use, copy, modify, merge, publish, */ +/* distribute, sublicense, and/or sell copies of the Software, and to */ +/* permit persons to whom the Software is furnished to do so, subject to */ +/* the following conditions: */ +/* */ +/* The above copyright notice and this permission notice shall be */ +/* included in all copies or substantial portions of the Software. */ +/* */ +/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ +/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ +/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ +/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ +/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ +/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ +/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +/*************************************************************************/ + +#ifdef UNIX_ENABLED + +#include "syslog_logger.h" +#include "print_string.h" +#include <syslog.h> + +void SyslogLogger::logv(const char *p_format, va_list p_list, bool p_err) { + if (!should_log(p_err)) { + return; + } + + vsyslog(p_err ? LOG_ERR : LOG_INFO, p_format, p_list); +} + +void SyslogLogger::print_error(const char *p_function, const char *p_file, int p_line, const char *p_code, const char *p_rationale, ErrorType p_type) { + if (!should_log(true)) { + return; + } + + const char *err_type = "**ERROR**"; + switch (p_type) { + case ERR_ERROR: err_type = "**ERROR**"; break; + case ERR_WARNING: err_type = "**WARNING**"; break; + case ERR_SCRIPT: err_type = "**SCRIPT ERROR**"; break; + case ERR_SHADER: err_type = "**SHADER ERROR**"; break; + default: ERR_PRINT("Unknown error type"); break; + } + + const char *err_details; + if (p_rationale && *p_rationale) + err_details = p_rationale; + else + err_details = p_code; + + syslog(p_type == ERR_WARNING ? LOG_WARNING : LOG_ERR, "%s: %s\n At: %s:%i:%s() - %s", err_type, err_details, p_file, p_line, p_function, p_code); +} + +SyslogLogger::~SyslogLogger() { +} + +#endif
\ No newline at end of file diff --git a/drivers/unix/syslog_logger.h b/drivers/unix/syslog_logger.h new file mode 100644 index 0000000000..b3cf2f9e3a --- /dev/null +++ b/drivers/unix/syslog_logger.h @@ -0,0 +1,48 @@ +/*************************************************************************/ +/* syslog_logger.h */ +/*************************************************************************/ +/* This file is part of: */ +/* GODOT ENGINE */ +/* https://godotengine.org */ +/*************************************************************************/ +/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */ +/* Copyright (c) 2014-2017 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 SYSLOG_LOGGER_H +#define SYSLOG_LOGGER_H + +#ifdef UNIX_ENABLED + +#include "io/logger.h" + +class SyslogLogger : public Logger { +public: + virtual void logv(const char *p_format, va_list p_list, bool p_err); + 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(); +}; + +#endif + +#endif
\ No newline at end of file diff --git a/drivers/unix/tcp_server_posix.cpp b/drivers/unix/tcp_server_posix.cpp index f3f9ab82f1..5062a74b63 100644 --- a/drivers/unix/tcp_server_posix.cpp +++ b/drivers/unix/tcp_server_posix.cpp @@ -165,7 +165,7 @@ Ref<StreamPeerTCP> TCPServerPosix::take_connection() { Ref<StreamPeerTCPPosix> conn = memnew(StreamPeerTCPPosix); IP_Address ip; - int port; + int port = 0; _set_ip_addr_port(ip, port, &their_addr); conn->set_socket(fd, ip, port, sock_type); diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 6e01b5f524..eb86491dec 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -1,5 +1,5 @@ /*************************************************************************/ -/* audio_driver_wasapi.cpp */ +/* audio_driver_wasapi.cpp */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -65,6 +65,19 @@ Error AudioDriverWASAPI::init_device() { format_tag = pwfex->wFormatTag; bits_per_sample = pwfex->wBitsPerSample; + switch (channels) { + case 2: // Stereo + case 4: // Surround 3.1 + case 6: // Surround 5.1 + case 8: // Surround 7.1 + break; + + default: + ERR_PRINTS("WASAPI: Unsupported number of channels: " + itos(channels)); + ERR_FAIL_V(ERR_CANT_OPEN); + break; + } + if (format_tag == WAVE_FORMAT_EXTENSIBLE) { WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex; @@ -83,13 +96,6 @@ Error AudioDriverWASAPI::init_device() { } } - int latency = GLOBAL_DEF("audio/output_latency", 25); - buffer_size = closest_power_of_2(latency * mix_rate / 1000); - - if (OS::get_singleton()->is_stdout_verbose()) { - print_line("audio buffer size: " + itos(buffer_size)); - } - hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK, 0, 0, pwfex, NULL); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); @@ -102,11 +108,21 @@ Error AudioDriverWASAPI::init_device() { hr = audio_client->GetService(IID_IAudioRenderClient, (void **)&render_client); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + UINT32 max_frames; hr = audio_client->GetBufferSize(&max_frames); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); + // Due to WASAPI Shared Mode we have no control of the buffer size + buffer_frames = max_frames; + + // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) + buffer_size = buffer_frames * channels; samples_in.resize(buffer_size); - buffer_frames = buffer_size / channels; + + if (OS::get_singleton()->is_stdout_verbose()) { + print_line("WASAPI: detected " + itos(channels) + " channels"); + print_line("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); + } return OK; } @@ -171,7 +187,7 @@ int AudioDriverWASAPI::get_mix_rate() const { AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const { - return SPEAKER_MODE_STEREO; + return get_speaker_mode_by_total_channels(channels); } void AudioDriverWASAPI::thread_func(void *p_udata) { @@ -200,7 +216,7 @@ void AudioDriverWASAPI::thread_func(void *p_udata) { HRESULT hr = ad->audio_client->GetCurrentPadding(&cur_frames); if (hr == S_OK) { // Check how much frames are available on the WASAPI buffer - UINT32 avail_frames = ad->max_frames - cur_frames; + UINT32 avail_frames = ad->buffer_frames - cur_frames; UINT32 write_frames = avail_frames > left_frames ? left_frames : avail_frames; BYTE *buffer = NULL; @@ -332,7 +348,6 @@ AudioDriverWASAPI::AudioDriverWASAPI() { mutex = NULL; thread = NULL; - max_frames = 0; format_tag = 0; bits_per_sample = 0; diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h index b91751f87e..fab8ab3250 100644 --- a/drivers/wasapi/audio_driver_wasapi.h +++ b/drivers/wasapi/audio_driver_wasapi.h @@ -1,5 +1,5 @@ /*************************************************************************/ -/* audio_driver_wasapi.h */ +/* audio_driver_wasapi.h */ /*************************************************************************/ /* This file is part of: */ /* GODOT ENGINE */ @@ -48,7 +48,6 @@ class AudioDriverWASAPI : public AudioDriver { Mutex *mutex; Thread *thread; - UINT32 max_frames; WORD format_tag; WORD bits_per_sample; diff --git a/drivers/windows/dir_access_windows.cpp b/drivers/windows/dir_access_windows.cpp index 6d6a6027d9..0bc4201ba3 100644 --- a/drivers/windows/dir_access_windows.cpp +++ b/drivers/windows/dir_access_windows.cpp @@ -162,10 +162,10 @@ Error DirAccessWindows::make_dir(String p_dir) { GLOBAL_LOCK_FUNCTION + p_dir = fix_path(p_dir); if (p_dir.is_rel_path()) - p_dir = get_current_dir().plus_file(p_dir); + p_dir = current_dir.plus_file(p_dir); - p_dir = fix_path(p_dir); p_dir = p_dir.replace("/", "\\"); bool success; diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index 30c8332fa3..3b6e469c9c 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -156,10 +156,11 @@ void FileAccessWindows::seek_end(int64_t p_position) { if (fseek(f, p_position, SEEK_END)) check_errors(); } -size_t FileAccessWindows::get_pos() const { +size_t FileAccessWindows::get_position() const { size_t aux_position = 0; - if (!(aux_position = ftell(f))) { + aux_position = ftell(f); + if (!aux_position) { check_errors(); }; return aux_position; @@ -168,9 +169,9 @@ size_t FileAccessWindows::get_len() const { ERR_FAIL_COND_V(!f, 0); - size_t pos = get_pos(); + size_t pos = get_position(); fseek(f, 0, SEEK_END); - int size = get_pos(); + int size = get_position(); fseek(f, pos, SEEK_SET); return size; @@ -206,6 +207,12 @@ Error FileAccessWindows::get_error() const { return last_error; } +void FileAccessWindows::flush() { + + ERR_FAIL_COND(!f); + fflush(f); +} + void FileAccessWindows::store_8(uint8_t p_dest) { ERR_FAIL_COND(!f); diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h index 6956e7855a..e5e7fd4a13 100644 --- a/drivers/windows/file_access_windows.h +++ b/drivers/windows/file_access_windows.h @@ -54,7 +54,7 @@ public: virtual void seek(size_t p_position); ///< seek to a given position virtual void seek_end(int64_t p_position = 0); ///< seek from the end of file - virtual size_t get_pos() const; ///< get position in the file + virtual size_t get_position() const; ///< get position in the file virtual size_t get_len() const; ///< get size of the file virtual bool eof_reached() const; ///< reading passed EOF @@ -64,6 +64,7 @@ public: virtual Error get_error() const; ///< get last error + virtual void flush(); virtual void store_8(uint8_t p_dest); ///< store a byte virtual bool file_exists(const String &p_name); ///< return true if a file exists |