diff options
Diffstat (limited to 'drivers')
70 files changed, 3235 insertions, 1166 deletions
diff --git a/drivers/SCsub b/drivers/SCsub index f9cfa3fb05..320d4dc4bb 100644 --- a/drivers/SCsub +++ b/drivers/SCsub @@ -4,9 +4,6 @@ Import('env') env.drivers_sources = [] -if 'builtin_zlib' in env and env['builtin_zlib']: - SConscript("zlib/SCsub") - # OS drivers SConscript('unix/SCsub') SConscript('windows/SCsub') diff --git a/drivers/alsa/SCsub b/drivers/alsa/SCsub index ee39fd2631..28b315ae66 100644 --- a/drivers/alsa/SCsub +++ b/drivers/alsa/SCsub @@ -3,5 +3,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/alsamidi/SCsub b/drivers/alsamidi/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/alsamidi/SCsub +++ b/drivers/alsamidi/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/convex_decomp/SCsub b/drivers/convex_decomp/SCsub index f017e55120..65ba5332b7 100644 --- a/drivers/convex_decomp/SCsub +++ b/drivers/convex_decomp/SCsub @@ -11,6 +11,7 @@ thirdparty_sources = [ "b2Triangle.cpp", ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env.add_source_files(env.drivers_sources, thirdparty_sources) -Export('env') +env_thirdparty = env.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) diff --git a/drivers/coreaudio/SCsub b/drivers/coreaudio/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/coreaudio/SCsub +++ b/drivers/coreaudio/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp index 09e50e4aaa..850b90d59b 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.cpp +++ b/drivers/coreaudio/audio_driver_coreaudio.cpp @@ -95,11 +95,6 @@ Error AudioDriverCoreAudio::init() { result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this); ERR_FAIL_COND_V(result != noErr, FAILED); - - prop.mSelector = kAudioHardwarePropertyDefaultInputDevice; - - result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); - ERR_FAIL_COND_V(result != noErr, FAILED); #endif AudioStreamBasicDescription strdesc; @@ -123,26 +118,6 @@ Error AudioDriverCoreAudio::init() { break; } - zeromem(&strdesc, sizeof(strdesc)); - size = sizeof(strdesc); - result = AudioUnitGetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size); - ERR_FAIL_COND_V(result != noErr, FAILED); - - switch (strdesc.mChannelsPerFrame) { - case 1: // Mono - capture_channels = 1; - break; - - case 2: // Stereo - capture_channels = 2; - break; - - default: - // Unknown number of channels, default to stereo - capture_channels = 2; - break; - } - mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); zeromem(&strdesc, sizeof(strdesc)); @@ -158,11 +133,6 @@ Error AudioDriverCoreAudio::init() { result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc)); ERR_FAIL_COND_V(result != noErr, FAILED); - strdesc.mChannelsPerFrame = capture_channels; - - result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc)); - ERR_FAIL_COND_V(result != noErr, FAILED); - int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY); // Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels) buffer_frames = closest_power_of_2(latency * mix_rate / 1000); @@ -175,9 +145,6 @@ Error AudioDriverCoreAudio::init() { unsigned int buffer_size = buffer_frames * channels; samples_in.resize(buffer_size); input_buf.resize(buffer_size); - input_buffer.resize(buffer_size * 8); - input_position = 0; - input_size = 0; print_verbose("CoreAudio: detected " + itos(channels) + " channels"); print_verbose("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); @@ -189,16 +156,10 @@ Error AudioDriverCoreAudio::init() { result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback)); ERR_FAIL_COND_V(result != noErr, FAILED); - zeromem(&callback, sizeof(AURenderCallbackStruct)); - callback.inputProc = &AudioDriverCoreAudio::input_callback; - callback.inputProcRefCon = this; - result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback)); - ERR_FAIL_COND_V(result != noErr, FAILED); - result = AudioUnitInitialize(audio_unit); ERR_FAIL_COND_V(result != noErr, FAILED); - return OK; + return capture_init(); } OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon, @@ -265,7 +226,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, bufferList.mBuffers[0].mNumberChannels = ad->capture_channels; bufferList.mBuffers[0].mDataByteSize = ad->input_buf.size() * sizeof(int16_t); - OSStatus result = AudioUnitRender(ad->audio_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList); + OSStatus result = AudioUnitRender(ad->input_unit, ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList); if (result == noErr) { for (int i = 0; i < inNumberFrames * ad->capture_channels; i++) { int32_t sample = ad->input_buf[i] << 16; @@ -277,7 +238,7 @@ OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon, } } } else { - ERR_PRINT(("AudioUnitRender failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioUnitRender failed, code: " + itos(result)); } ad->unlock(); @@ -289,7 +250,7 @@ void AudioDriverCoreAudio::start() { if (!active) { OSStatus result = AudioOutputUnitStart(audio_unit); if (result != noErr) { - ERR_PRINT(("AudioOutputUnitStart failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result)); } else { active = true; } @@ -300,7 +261,7 @@ void AudioDriverCoreAudio::stop() { if (active) { OSStatus result = AudioOutputUnitStop(audio_unit); if (result != noErr) { - ERR_PRINT(("AudioOutputUnitStop failed, code: " + itos(result)).utf8().get_data()); + ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result)); } else { active = false; } @@ -332,6 +293,8 @@ bool AudioDriverCoreAudio::try_lock() { } void AudioDriverCoreAudio::finish() { + capture_finish(); + if (audio_unit) { OSStatus result; @@ -375,6 +338,7 @@ void AudioDriverCoreAudio::finish() { ERR_PRINT("AudioComponentInstanceDispose failed"); } + audio_unit = NULL; unlock(); } @@ -384,20 +348,160 @@ void AudioDriverCoreAudio::finish() { } } -Error AudioDriverCoreAudio::capture_start() { +Error AudioDriverCoreAudio::capture_init() { + AudioComponentDescription desc; + zeromem(&desc, sizeof(desc)); + desc.componentType = kAudioUnitType_Output; +#ifdef OSX_ENABLED + desc.componentSubType = kAudioUnitSubType_HALOutput; +#else + desc.componentSubType = kAudioUnitSubType_RemoteIO; +#endif + desc.componentManufacturer = kAudioUnitManufacturer_Apple; + + AudioComponent comp = AudioComponentFindNext(NULL, &desc); + ERR_FAIL_COND_V(comp == NULL, FAILED); + + OSStatus result = AudioComponentInstanceNew(comp, &input_unit); + ERR_FAIL_COND_V(result != noErr, FAILED); + +#ifdef OSX_ENABLED + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultInputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; + + result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); + ERR_FAIL_COND_V(result != noErr, FAILED); +#endif UInt32 flag = 1; - OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); + result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); + ERR_FAIL_COND_V(result != noErr, FAILED); + flag = 0; + result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, kOutputBus, &flag, sizeof(flag)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + UInt32 size; +#ifdef OSX_ENABLED + AudioDeviceID deviceId; + size = sizeof(AudioDeviceID); + AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultInputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster }; + + result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId); + ERR_FAIL_COND_V(result != noErr, FAILED); + + result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID)); + ERR_FAIL_COND_V(result != noErr, FAILED); +#endif + + AudioStreamBasicDescription strdesc; + zeromem(&strdesc, sizeof(strdesc)); + size = sizeof(strdesc); + result = AudioUnitGetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, &size); + ERR_FAIL_COND_V(result != noErr, FAILED); + + switch (strdesc.mChannelsPerFrame) { + case 1: // Mono + capture_channels = 1; + break; + + case 2: // Stereo + capture_channels = 2; + break; + + default: + // Unknown number of channels, default to stereo + capture_channels = 2; + break; + } + + mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE); + + zeromem(&strdesc, sizeof(strdesc)); + strdesc.mFormatID = kAudioFormatLinearPCM; + strdesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; + strdesc.mChannelsPerFrame = capture_channels; + strdesc.mSampleRate = mix_rate; + strdesc.mFramesPerPacket = 1; + strdesc.mBitsPerChannel = 16; + strdesc.mBytesPerFrame = strdesc.mBitsPerChannel * strdesc.mChannelsPerFrame / 8; + strdesc.mBytesPerPacket = strdesc.mBytesPerFrame * strdesc.mFramesPerPacket; + + result = AudioUnitSetProperty(input_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &strdesc, sizeof(strdesc)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + callback.inputProc = &AudioDriverCoreAudio::input_callback; + callback.inputProcRefCon = this; + result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callback, sizeof(callback)); + ERR_FAIL_COND_V(result != noErr, FAILED); + + result = AudioUnitInitialize(input_unit); ERR_FAIL_COND_V(result != noErr, FAILED); return OK; } +void AudioDriverCoreAudio::capture_finish() { + if (input_unit) { + lock(); + + AURenderCallbackStruct callback; + zeromem(&callback, sizeof(AURenderCallbackStruct)); + OSStatus result = AudioUnitSetProperty(input_unit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, 0, &callback, sizeof(callback)); + if (result != noErr) { + ERR_PRINT("AudioUnitSetProperty failed"); + } + + result = AudioUnitUninitialize(input_unit); + if (result != noErr) { + ERR_PRINT("AudioUnitUninitialize failed"); + } + +#ifdef OSX_ENABLED + AudioObjectPropertyAddress prop; + prop.mSelector = kAudioHardwarePropertyDefaultInputDevice; + prop.mScope = kAudioObjectPropertyScopeGlobal; + prop.mElement = kAudioObjectPropertyElementMaster; + + result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &input_device_address_cb, this); + if (result != noErr) { + ERR_PRINT("AudioObjectRemovePropertyListener failed"); + } +#endif + + result = AudioComponentInstanceDispose(input_unit); + if (result != noErr) { + ERR_PRINT("AudioComponentInstanceDispose failed"); + } + + input_unit = NULL; + unlock(); + } +} + +Error AudioDriverCoreAudio::capture_start() { + + input_buffer_init(buffer_frames); + + OSStatus result = AudioOutputUnitStart(input_unit); + if (result != noErr) { + ERR_PRINTS("AudioOutputUnitStart failed, code: " + itos(result)); + } + + return OK; +} + Error AudioDriverCoreAudio::capture_stop() { - UInt32 flag = 0; - OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag)); - ERR_FAIL_COND_V(result != noErr, FAILED); + if (input_unit) { + OSStatus result = AudioOutputUnitStop(input_unit); + if (result != noErr) { + ERR_PRINTS("AudioOutputUnitStop failed, code: " + itos(result)); + } + } return OK; } @@ -531,12 +635,14 @@ void AudioDriverCoreAudio::_set_device(const String &device, bool capture) { } if (found) { - OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, capture ? kInputBus : kOutputBus, &deviceId, sizeof(AudioDeviceID)); + OSStatus result = AudioUnitSetProperty(capture ? input_unit : audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID)); ERR_FAIL_COND(result != noErr); - // Reset audio input to keep synchronisation. - input_position = 0; - input_size = 0; + if (capture) { + // Reset audio input to keep synchronisation. + input_position = 0; + input_size = 0; + } } } @@ -580,6 +686,7 @@ String AudioDriverCoreAudio::capture_get_device() { AudioDriverCoreAudio::AudioDriverCoreAudio() { audio_unit = NULL; + input_unit = NULL; active = false; mutex = NULL; diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h index d3f7c8d596..474a9e43ae 100644 --- a/drivers/coreaudio/audio_driver_coreaudio.h +++ b/drivers/coreaudio/audio_driver_coreaudio.h @@ -43,6 +43,7 @@ class AudioDriverCoreAudio : public AudioDriver { AudioComponentInstance audio_unit; + AudioComponentInstance input_unit; bool active; Mutex *mutex; @@ -83,6 +84,9 @@ class AudioDriverCoreAudio : public AudioDriver { UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData); + Error capture_init(); + void capture_finish(); + public: const char *get_name() const { return "CoreAudio"; diff --git a/drivers/coremidi/SCsub b/drivers/coremidi/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/coremidi/SCsub +++ b/drivers/coremidi/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/coremidi/core_midi.cpp b/drivers/coremidi/core_midi.cpp index e8106c4543..2ebbabaa38 100644 --- a/drivers/coremidi/core_midi.cpp +++ b/drivers/coremidi/core_midi.cpp @@ -51,13 +51,13 @@ Error MIDIDriverCoreMidi::open() { OSStatus result = MIDIClientCreate(name, NULL, NULL, &client); CFRelease(name); if (result != noErr) { - ERR_PRINTS("MIDIClientCreate failed: " + String(GetMacOSStatusErrorString(result))); + ERR_PRINTS("MIDIClientCreate failed, code: " + itos(result)); return ERR_CANT_OPEN; } result = MIDIInputPortCreate(client, CFSTR("Godot Input"), MIDIDriverCoreMidi::read, (void *)this, &port_in); if (result != noErr) { - ERR_PRINTS("MIDIInputPortCreate failed: " + String(GetMacOSStatusErrorString(result))); + ERR_PRINTS("MIDIInputPortCreate failed, code: " + itos(result)); return ERR_CANT_OPEN; } @@ -65,7 +65,7 @@ Error MIDIDriverCoreMidi::open() { for (int i = 0; i < sources; i++) { MIDIEndpointRef source = MIDIGetSource(i); - if (source != NULL) { + if (source) { MIDIPortConnectSource(port_in, source, (void *)this); connected_sources.insert(i, source); } diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h index 126f23feeb..dfdb3a6bba 100644 --- a/drivers/dummy/rasterizer_dummy.h +++ b/drivers/dummy/rasterizer_dummy.h @@ -63,7 +63,8 @@ public: void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_far_amount, VS::EnvironmentDOFBlurQuality p_quality) {} - void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) {} + void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) {} + void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {} void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_int, float p_fade_out, float p_depth_tolerance, bool p_roughness) {} @@ -74,7 +75,7 @@ public: void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {} void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) {} - void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) {} + void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) {} void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) {} bool is_environment(RID p_env) { return false; } @@ -517,6 +518,7 @@ public: void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) {} void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) {} void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) {} + void reflection_probe_set_resolution(RID p_probe, int p_resolution) {} AABB reflection_probe_get_aabb(RID p_probe) const { return AABB(); } VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const { return VisualServer::REFLECTION_PROBE_UPDATE_ONCE; } @@ -583,22 +585,12 @@ public: SelfList<RasterizerScene::InstanceBase>::List instance_list; - _FORCE_INLINE_ void instance_change_notify() { + _FORCE_INLINE_ void instance_change_notify(bool p_aabb = true, bool p_materials = true) { SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); while (instances) { - instances->self()->base_changed(); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_material_change_notify() { - - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - - instances->self()->base_material_changed(); + instances->self()->base_changed(p_aabb, p_materials); instances = instances->next(); } } @@ -690,6 +682,8 @@ public: int particles_get_draw_passes(RID p_particles) const { return 0; } RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const { return RID(); } + virtual bool particles_is_inactive(RID p_particles) const { return false; } + /* RENDER TARGET */ RID render_target_create() { return RID(); } @@ -787,6 +781,7 @@ public: void restore_render_target() {} void clear_render_target(const Color &p_color) {} void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0) {} + void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) {} void end_frame(bool p_swap_buffers) {} void finalize() {} @@ -802,6 +797,8 @@ public: _create_func = _create_current; } + virtual bool is_low_end() const { return true; } + RasterizerDummy() {} ~RasterizerDummy() {} }; diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub index 4d66a9f9f1..efb26a7908 100644 --- a/drivers/gl_context/SCsub +++ b/drivers/gl_context/SCsub @@ -10,13 +10,14 @@ if (env["platform"] in ["haiku", "osx", "windows", "x11"]): ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - env.add_source_files(env.drivers_sources, thirdparty_sources) env.Append(CPPPATH=[thirdparty_dir]) env.Append(CPPFLAGS=['-DGLAD_ENABLED']) env.Append(CPPFLAGS=['-DGLES_OVER_GL']) + env_thirdparty = env.Clone() + env_thirdparty.disable_warnings() + env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) + # Godot source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/gles2/SCsub b/drivers/gles2/SCsub index 2471dd3739..9923e52c73 100644 --- a/drivers/gles2/SCsub +++ b/drivers/gles2/SCsub @@ -2,6 +2,6 @@ Import('env') -env.add_source_files(env.drivers_sources,"*.cpp") +env.add_source_files(env.drivers_sources, "*.cpp") SConscript("shaders/SCsub") diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp index 4ae4441462..9227c04e71 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.cpp +++ b/drivers/gles2/rasterizer_canvas_gles2.cpp @@ -811,8 +811,6 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons bool rebind_shader = true; - Size2 rt_size = Size2(storage->frame.current_rt->width, storage->frame.current_rt->height); - state.current_tex = RID(); state.current_tex_ptr = NULL; state.current_normal = RID(); @@ -1051,6 +1049,43 @@ void RasterizerCanvasGLES2::draw_generic_textured_rect(const Rect2 &p_rect, cons glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } +void RasterizerCanvasGLES2::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + Vector2 half_size; + if (storage->frame.current_rt) { + half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height); + } else { + half_size = OS::get_singleton()->get_window_size(); + } + half_size *= 0.5; + Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y); + Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y); + + float aspect_ratio = p_rect.size.x / p_rect.size.y; + + // setup our lens shader + state.lens_shader.bind(); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::OFFSET, offset); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::SCALE, scale); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::K1, p_k1); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::K2, p_k2); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::EYE_CENTER, p_eye_center); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::UPSCALE, p_oversample); + state.lens_shader.set_uniform(LensDistortedShaderGLES2::ASPECT_RATIO, aspect_ratio); + + // bind our quad buffer + _bind_quad_buffer(); + + // and draw + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + // and cleanup + glBindBuffer(GL_ARRAY_BUFFER, 0); + + for (int i = 0; i < VS::ARRAY_MAX; i++) { + glDisableVertexAttribArray(i); + } +} + void RasterizerCanvasGLES2::draw_window_margins(int *black_margin, RID *black_image) { } @@ -1076,6 +1111,7 @@ void RasterizerCanvasGLES2::initialize() { // polygon buffer { uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); poly_size *= 1024; poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); glGenBuffers(1, &data.polygon_buffer); @@ -1087,6 +1123,7 @@ void RasterizerCanvasGLES2::initialize() { glBindBuffer(GL_ARRAY_BUFFER, 0); uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); index_size *= 1024; // kb glGenBuffers(1, &data.polygon_index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); @@ -1150,7 +1187,6 @@ void RasterizerCanvasGLES2::initialize() { _EIDX(1, 1), _EIDX(1, 2), _EIDX(2, 2), _EIDX(2, 2), _EIDX(2, 1), _EIDX(1, 1) }; - ; #undef _EIDX glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(elems), elems, GL_STATIC_DRAW); @@ -1163,6 +1199,10 @@ void RasterizerCanvasGLES2::initialize() { state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true); state.canvas_shader.bind(); + + state.lens_shader.init(); + + state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_PIXEL_SNAP, GLOBAL_DEF("rendering/quality/2d/use_pixel_snap", false)); } void RasterizerCanvasGLES2::finalize() { diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h index cda3ec79e7..cf1c239b6e 100644 --- a/drivers/gles2/rasterizer_canvas_gles2.h +++ b/drivers/gles2/rasterizer_canvas_gles2.h @@ -34,6 +34,7 @@ #include "servers/visual/rasterizer.h" #include "shaders/canvas.glsl.gen.h" +#include "shaders/lens_distorted.glsl.gen.h" // #include "shaders/canvas_shadow.glsl.gen.h" @@ -70,6 +71,7 @@ public: bool canvas_texscreen_used; CanvasShaderGLES2 canvas_shader; // CanvasShadowShaderGLES3 canvas_shadow_shader; + LensDistortedShaderGLES2 lens_shader; bool using_texture_rect; bool using_ninepatch; @@ -117,6 +119,7 @@ public: void _bind_quad_buffer(); void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); + void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); void initialize(); void finalize(); diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp index bd03bd71f6..f49dbfeabb 100644 --- a/drivers/gles2/rasterizer_gles2.cpp +++ b/drivers/gles2/rasterizer_gles2.cpp @@ -32,7 +32,7 @@ #include "core/os/os.h" #include "core/project_settings.h" -#include "gl_context/context_gl.h" +#include "drivers/gl_context/context_gl.h" #define _EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB 0x8242 #define _EXT_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH_ARB 0x8243 @@ -58,12 +58,29 @@ #define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 #define _EXT_DEBUG_OUTPUT 0x92E0 -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) +#ifndef GLAPIENTRY +#if defined(WINDOWS_ENABLED) && !defined(UWP_ENABLED) #define GLAPIENTRY APIENTRY #else #define GLAPIENTRY #endif +#endif + +#if !defined(GLES_OVER_GL) && !defined(IPHONE_ENABLED) +// Used for debugging on mobile, but not iOS as EGL is not available +#include <GLES2/gl2.h> +#include <GLES2/gl2ext.h> +#include <GLES2/gl2platform.h> + +#include <EGL/egl.h> +#include <EGL/eglext.h> +#endif +#if defined(MINGW_ENABLED) || defined(_MSC_VER) +#define strcpy strcpy_s +#endif + +#ifndef IPHONE_ENABLED static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) { if (type == _EXT_DEBUG_TYPE_OTHER_ARB) @@ -73,6 +90,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL return; //these are ultimately annoying, so removing for now char debSource[256], debType[256], debSev[256]; + if (source == _EXT_DEBUG_SOURCE_API_ARB) strcpy(debSource, "OpenGL"); else if (source == _EXT_DEBUG_SOURCE_WINDOW_SYSTEM_ARB) @@ -110,6 +128,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL ERR_PRINTS(output); } +#endif // IPHONE_ENABLED typedef void (*DEBUGPROCARB)(GLenum source, GLenum type, @@ -179,7 +198,7 @@ Error RasterizerGLES2::is_viable() { return ERR_UNAVAILABLE; } } -#endif +#endif // GLES_OVER_GL #endif // GLAD_ENABLED @@ -191,7 +210,7 @@ void RasterizerGLES2::initialize() { print_verbose("Using GLES2 video driver"); #ifdef GLAD_ENABLED - if (true || OS::get_singleton()->is_stdout_verbose()) { + if (OS::get_singleton()->is_stdout_verbose()) { if (GLAD_GL_ARB_debug_output) { glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); glDebugMessageCallbackARB(_gl_debug_print, NULL); @@ -204,7 +223,7 @@ void RasterizerGLES2::initialize() { // For debugging #ifdef GLES_OVER_GL - if (GLAD_GL_ARB_debug_output) { + if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) { glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, NULL, GL_TRUE); @@ -217,7 +236,24 @@ void RasterizerGLES2::initialize() { GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello"); */ } -#endif +#else +#ifndef IPHONE_ENABLED + if (OS::get_singleton()->is_stdout_verbose()) { + DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback"); + if (!callback) { + callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR"); + } + + if (callback) { + + print_line("godot: ENABLING GL DEBUG"); + glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB); + callback(_gl_debug_print, NULL); + glEnable(_EXT_DEBUG_OUTPUT); + } + } +#endif // !IPHONE_ENABLED +#endif // GLES_OVER_GL const GLubyte *renderer = glGetString(GL_RENDERER); print_line("OpenGL ES 2.0 Renderer: " + String((const char *)renderer)); @@ -380,6 +416,26 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re canvas->canvas_end(); } +void RasterizerGLES2::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + ERR_FAIL_COND(storage->frame.current_rt); + + RasterizerStorageGLES2::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + glDisable(GL_BLEND); + + // render to our framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo); + + // output our texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rt->color); + + canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample); + + glBindTexture(GL_TEXTURE_2D, 0); +} + void RasterizerGLES2::end_frame(bool p_swap_buffers) { if (OS::get_singleton()->is_layered_allowed()) { diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h index c76d5f7f20..97f8ee7c1c 100644 --- a/drivers/gles2/rasterizer_gles2.h +++ b/drivers/gles2/rasterizer_gles2.h @@ -59,6 +59,7 @@ public: virtual void restore_render_target(); virtual void clear_render_target(const Color &p_color); virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0); + virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); virtual void end_frame(bool p_swap_buffers); virtual void finalize(); @@ -66,6 +67,8 @@ public: static void make_current(); static void register_config(); + virtual bool is_low_end() const { return true; } + RasterizerGLES2(); ~RasterizerGLES2(); }; diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp index 56605a9fe5..7addbaa9fe 100644 --- a/drivers/gles2/rasterizer_scene_gles2.cpp +++ b/drivers/gles2/rasterizer_scene_gles2.cpp @@ -42,6 +42,8 @@ #define glClearDepth glClearDepthf #endif +#define _DEPTH_COMPONENT24_OES 0x81A6 + static const GLenum _cube_side_enum[6] = { GL_TEXTURE_CUBE_MAP_NEGATIVE_X, @@ -437,29 +439,203 @@ void RasterizerSceneGLES2::reflection_atlas_set_subdivision(RID p_ref_atlas, int //////////////////////////////////////////////////// RID RasterizerSceneGLES2::reflection_probe_instance_create(RID p_probe) { - return RID(); + + RasterizerStorageGLES2::ReflectionProbe *probe = storage->reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!probe, RID()); + + ReflectionProbeInstance *rpi = memnew(ReflectionProbeInstance); + + rpi->probe_ptr = probe; + rpi->self = reflection_probe_instance_owner.make_rid(rpi); + rpi->probe = p_probe; + rpi->reflection_atlas_index = -1; + rpi->render_step = -1; + rpi->last_pass = 0; + rpi->current_resolution = 0; + rpi->dirty = true; + + rpi->last_pass = 0; + rpi->index = 0; + + for (int i = 0; i < 6; i++) { + glGenFramebuffers(1, &rpi->fbo[i]); + } + + glGenFramebuffers(1, &rpi->fbo_blur); + glGenRenderbuffers(1, &rpi->depth); + rpi->cubemap = 0; + //glGenTextures(1, &rpi->cubemap); + + return rpi->self; } void RasterizerSceneGLES2::reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform) { + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND(!rpi); + rpi->transform = p_transform; } void RasterizerSceneGLES2::reflection_probe_release_atlas_index(RID p_instance) { } bool RasterizerSceneGLES2::reflection_probe_instance_needs_redraw(RID p_instance) { - return false; + const ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + bool need_redraw = rpi->probe_ptr->resolution != rpi->current_resolution || rpi->dirty || rpi->probe_ptr->update_mode == VS::REFLECTION_PROBE_UPDATE_ALWAYS; + rpi->dirty = false; + return need_redraw; } bool RasterizerSceneGLES2::reflection_probe_instance_has_reflection(RID p_instance) { - return false; + return true; } bool RasterizerSceneGLES2::reflection_probe_instance_begin_render(RID p_instance, RID p_reflection_atlas) { - return false; + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + rpi->render_step = 0; + + if (rpi->probe_ptr->resolution != rpi->current_resolution) { + + //update cubemap if resolution changed + int size = rpi->probe_ptr->resolution; + rpi->current_resolution = size; + + GLenum internal_format = GL_RGB; + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; + + glActiveTexture(GL_TEXTURE0); + if (rpi->cubemap != 0) { + glDeleteTextures(1, &rpi->cubemap); + } + glGenTextures(1, &rpi->cubemap); + glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); +#if 1 + //Mobile hardware (PowerVR specially) prefers this approach, the other one kills the game + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL); + } + + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); + + glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); //resize depth buffer + glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size); + + for (int i = 0; i < 6; i++) { + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); + } + +#else + int lod = 0; + + //the approach below is fatal for powervr + + // Set the initial (empty) mipmaps, all need to be set for this to work in GLES2, even if later wont be used. + while (size >= 1) { + + for (int i = 0; i < 6; i++) { + glTexImage2D(_cube_side_enum[i], lod, internal_format, size, size, 0, format, type, NULL); + if (size == rpi->current_resolution) { + //adjust framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo[i]); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, 0); + glBindRenderbuffer(GL_RENDERBUFFER, rpi->depth); + glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, size, size); + glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rpi->depth); + +#ifdef DEBUG_ENABLED + GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); + ERR_CONTINUE(status != GL_FRAMEBUFFER_COMPLETE); +#endif + } + } + + lod++; + + size >>= 1; + } +#endif + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } + + return true; } bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_instance) { - return false; + + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_instance); + ERR_FAIL_COND_V(!rpi, false); + + int size = rpi->probe_ptr->resolution; + + { + glBindBuffer(GL_ARRAY_BUFFER, 0); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); + glDisable(GL_CULL_FACE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_SCISSOR_TEST); + glDisable(GL_BLEND); + glDepthMask(GL_FALSE); + + for (int i = 0; i < VS::ARRAY_MAX - 1; i++) { + glDisableVertexAttribArray(i); + } + } + + //vdc cache + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, storage->resources.radical_inverse_vdc_cache_tex); + + glBindFramebuffer(GL_FRAMEBUFFER, rpi->fbo_blur); + // now render to the framebuffer, mipmap level for mipmap level + int lod = 1; + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_CUBE_MAP, rpi->cubemap); + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR); //use linear, no mipmaps so it does not read from what is being written to + + size >>= 1; + int mipmaps = 6; + + storage->shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, false); + storage->shaders.cubemap_filter.bind(); + + //blur + while (size >= 1) { + + for (int i = 0; i < 6; i++) { + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], rpi->cubemap, lod); + + glViewport(0, 0, size, size); + storage->bind_quad_array(); + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); + float roughness = CLAMP(lod / (float)(mipmaps - 1), 0, 1); + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness); + storage->shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::Z_FLIP, false); + + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + } + + size >>= 1; + + lod++; + } + + // restore ranges + + glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); + glBindFramebuffer(GL_FRAMEBUFFER, 0); + + return true; } /* ENVIRONMENT API */ @@ -532,7 +708,7 @@ void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enabl ERR_FAIL_COND(!env); } -void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) { +void RasterizerSceneGLES2::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); } @@ -563,20 +739,39 @@ void RasterizerSceneGLES2::environment_set_adjustment(RID p_env, bool p_enable, } void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + + env->fog_enabled = p_enable; + env->fog_color = p_color; + env->fog_sun_color = p_sun_color; + env->fog_sun_amount = p_sun_amount; } -void RasterizerSceneGLES2::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) { +void RasterizerSceneGLES2::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); + + env->fog_depth_enabled = p_enable; + env->fog_depth_begin = p_depth_begin; + env->fog_depth_end = p_depth_end; + env->fog_depth_curve = p_depth_curve; + env->fog_transmit_enabled = p_transmit; + env->fog_transmit_curve = p_transmit_curve; } void RasterizerSceneGLES2::environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve) { + Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); -} + env->fog_height_enabled = p_enable; + env->fog_height_min = p_min_height; + env->fog_height_max = p_max_height; + env->fog_height_curve = p_height_curve; +} bool RasterizerSceneGLES2::is_environment(RID p_env) { return environment_owner.owns(p_env); } @@ -712,10 +907,8 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G bool has_alpha = has_base_alpha || has_blend_alpha; bool mirror = p_instance->mirror; - bool no_cull = false; if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED) { - no_cull = true; mirror = false; } else if (p_material->shader->spatial.cull_mode == RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_FRONT) { mirror = !mirror; @@ -738,7 +931,6 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G //shader does not use discard and does not write a vertex position, use generic material if (p_instance->cast_shadows == VS::SHADOW_CASTING_SETTING_DOUBLE_SIDED) { p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material_twosided : default_material_twosided); - no_cull = true; mirror = false; } else { p_material = storage->material_owner.getptr(!p_shadow_pass && p_material->shader->spatial.uses_world_coordinates ? default_worldcoord_material : default_material); @@ -763,6 +955,7 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G e->use_accum = false; e->light_index = RenderList::MAX_LIGHTS; e->use_accum_ptr = &e->use_accum; + e->instancing = (e->instance->base_type == VS::INSTANCE_MULTIMESH) ? 1 : 0; if (e->geometry->last_pass != render_pass) { e->geometry->last_pass = render_pass; @@ -782,17 +975,39 @@ void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::G e->material_index = e->material->index; - e->refprobe_0_index = 0xFF; //refprobe disabled by default - e->refprobe_1_index = 0xFF; //refprobe disabled by default + e->refprobe_0_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default + e->refprobe_1_index = RenderList::MAX_REFLECTION_PROBES; //refprobe disabled by default if (!p_depth_pass) { e->depth_layer = e->instance->depth_layer; e->priority = p_material->render_priority; - //if (e->instance->reflection_probe_instances.size() > 0 ) { - // RasterizerStorageGLES2:: - //} + int rpsize = e->instance->reflection_probe_instances.size(); + if (rpsize > 0) { + bool first = true; + rpsize = MIN(rpsize, 2); //more than 2 per object are not supported, this keeps it stable + + for (int i = 0; i < rpsize; i++) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(e->instance->reflection_probe_instances[i]); + if (rpi->last_pass != render_pass) { + continue; + } + if (first) { + e->refprobe_0_index = rpi->index; + first = false; + } else { + e->refprobe_1_index = rpi->index; + break; + } + } + + /* if (e->refprobe_0_index > e->refprobe_1_index) { //if both are valid, swap them to keep order as best as possible + uint64_t tmp = e->refprobe_0_index; + e->refprobe_0_index = e->refprobe_1_index; + e->refprobe_1_index = tmp; + }*/ + } //add directional lights @@ -924,9 +1139,7 @@ void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p } break; - default: { - - } break; + default: {} } } } @@ -994,6 +1207,8 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size); + state.current_main_tex = 0; + for (int i = 0; i < tc; i++) { glActiveTexture(GL_TEXTURE0 + i); @@ -1024,6 +1239,9 @@ bool RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_m t = t->get_ptr(); glBindTexture(t->target, t->tex_id); + if (i == 0) { + state.current_main_tex = t->tex_id; + } } state.scene_shader.use_material((void *)p_material); @@ -1051,7 +1269,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste glDisableVertexAttribArray(i); switch (i) { case VS::ARRAY_NORMAL: { - glVertexAttrib4f(VS::ARRAY_COLOR, 0.0, 0.0, 1, 1); + glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); } break; case VS::ARRAY_COLOR: { glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); @@ -1136,8 +1354,6 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste bone_weight[3] = (weight_ptr[3] / (float)0xFFFF); } - size_t offset = i * 12; - Transform transform; Transform bone_transforms[4] = { @@ -1176,33 +1392,28 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste //enable transform buffer and bind it glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); - glEnableVertexAttribArray(VS::ARRAY_MAX + 0); - glEnableVertexAttribArray(VS::ARRAY_MAX + 1); - glEnableVertexAttribArray(VS::ARRAY_MAX + 2); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glEnableVertexAttribArray(INSTANCE_BONE_BASE + 2); - glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); - glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); - glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); + glVertexAttribPointer(INSTANCE_BONE_BASE + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0)); + glVertexAttribPointer(INSTANCE_BONE_BASE + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1)); + glVertexAttribPointer(INSTANCE_BONE_BASE + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2)); clear_skeleton_buffer = false; } } if (clear_skeleton_buffer) { - // just to make sure - glDisableVertexAttribArray(VS::ARRAY_MAX + 0); - glDisableVertexAttribArray(VS::ARRAY_MAX + 1); - glDisableVertexAttribArray(VS::ARRAY_MAX + 2); - glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 2); } } break; case VS::INSTANCE_MULTIMESH: { - RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner); RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry); glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id); @@ -1219,7 +1430,7 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste glDisableVertexAttribArray(i); switch (i) { case VS::ARRAY_NORMAL: { - glVertexAttrib4f(VS::ARRAY_COLOR, 0.0, 0.0, 1, 1); + glVertexAttrib4f(VS::ARRAY_NORMAL, 0.0, 0.0, 1, 1); } break; case VS::ARRAY_COLOR: { glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); @@ -1230,25 +1441,22 @@ void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, Raste } } - if (!storage->config.float_texture_supported) { - // just to make sure, clear skeleton buffer too - glDisableVertexAttribArray(VS::ARRAY_MAX + 0); - glDisableVertexAttribArray(VS::ARRAY_MAX + 1); - glDisableVertexAttribArray(VS::ARRAY_MAX + 2); - - glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); - glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); - } + // prepare multimesh (disable) + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 0); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 1); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 2); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 3); + glDisableVertexAttribArray(INSTANCE_ATTRIB_BASE + 4); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 0); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 1); + glDisableVertexAttribArray(INSTANCE_BONE_BASE + 2); } break; case VS::INSTANCE_IMMEDIATE: { } break; - default: { - - } break; + default: {} } } @@ -1267,7 +1475,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { } else { glDrawArrays(gl_primitive[s->primitive], 0, s->array_len); } - + /* if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) { //clean up after skeleton glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer); @@ -1280,7 +1488,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0); glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0); } - +*/ } break; case VS::INSTANCE_MULTIMESH: { @@ -1301,53 +1509,33 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { // drawing + const float *base_buffer = multi_mesh->data.ptr(); + for (int i = 0; i < amount; i++) { - float *buffer = &multi_mesh->data.write[i * stride]; + const float *buffer = base_buffer + i * stride; { - // inline of multimesh_get_transform since it's such a pain - // to get a RID from here... - Transform transform; - - transform.basis.elements[0][0] = buffer[0]; - transform.basis.elements[0][1] = buffer[1]; - transform.basis.elements[0][2] = buffer[2]; - transform.origin.x = buffer[3]; - transform.basis.elements[1][0] = buffer[4]; - transform.basis.elements[1][1] = buffer[5]; - transform.basis.elements[1][2] = buffer[6]; - transform.origin.y = buffer[7]; - transform.basis.elements[2][0] = buffer[8]; - transform.basis.elements[2][1] = buffer[9]; - transform.basis.elements[2][2] = buffer[10]; - transform.origin.z = buffer[11]; - - float row[3][4] = { - { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] }, - { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] }, - { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] }, - }; - - glVertexAttrib4fv(VS::ARRAY_MAX + 0, row[0]); - glVertexAttrib4fv(VS::ARRAY_MAX + 1, row[1]); - glVertexAttrib4fv(VS::ARRAY_MAX + 2, row[2]); + + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 0, &buffer[0]); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 1, &buffer[4]); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 2, &buffer[8]); } if (multi_mesh->color_floats) { if (multi_mesh->color_format == VS::MULTIMESH_COLOR_8BIT) { uint8_t *color_data = (uint8_t *)(buffer + color_ofs); - glVertexAttrib4f(VS::ARRAY_MAX + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 3, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0); } else { - glVertexAttrib4fv(VS::ARRAY_MAX + 3, buffer + color_ofs); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 3, buffer + color_ofs); } } if (multi_mesh->custom_data_floats) { if (multi_mesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) { uint8_t *custom_data = (uint8_t *)(buffer + custom_data_ofs); - glVertexAttrib4f(VS::ARRAY_MAX + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); + glVertexAttrib4f(INSTANCE_ATTRIB_BASE + 4, custom_data[0] / 255.0, custom_data[1] / 255.0, custom_data[2] / 255.0, custom_data[3] / 255.0); } else { - glVertexAttrib4fv(VS::ARRAY_MAX + 4, buffer + custom_data_ofs); + glVertexAttrib4fv(INSTANCE_ATTRIB_BASE + 4, buffer + custom_data_ofs); } } @@ -1471,6 +1659,7 @@ void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) { } } break; + default: {} } } @@ -1514,7 +1703,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas } state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, p_light->light_ptr->directional_blend_splits); - if (p_light->light_ptr->shadow) { + if (!state.render_no_shadows && p_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); glBindTexture(GL_TEXTURE_2D, directional_shadow.depth); @@ -1526,7 +1715,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas case VS::LIGHT_OMNI: { state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_OMNI, true); - if (shadow_atlas && p_light->light_ptr->shadow) { + if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); @@ -1537,7 +1726,7 @@ void RasterizerSceneGLES2::_setup_light_type(LightInstance *p_light, ShadowAtlas case VS::LIGHT_SPOT: { state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_MODE_SPOT, true); - if (shadow_atlas && p_light->light_ptr->shadow) { + if (!state.render_no_shadows && shadow_atlas && p_light->light_ptr->shadow) { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SHADOW, true); glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 3); glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth); @@ -1571,7 +1760,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado CameraMatrix matrices[4]; - if (light_ptr->shadow && directional_shadow.depth) { + if (!state.render_no_shadows && light_ptr->shadow && directional_shadow.depth) { int shadow_count = 0; Color split_offsets; @@ -1662,11 +1851,10 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + float attenuation = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation); - if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) { + if (!state.render_no_shadows && light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { uint32_t key = shadow_atlas->shadow_owners[light->self]; @@ -1716,8 +1904,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized(); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction); - Color attenuation = Color(0.0, 0.0, 0.0, 0.0); - attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; + float attenuation = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION]; float range = light_ptr->param[VS::LIGHT_PARAM_RANGE]; float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION]; float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE]; @@ -1728,7 +1915,7 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle); state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range); - if (light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { + if (!state.render_no_shadows && light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) { uint32_t key = shadow_atlas->shadow_owners[light->self]; uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03; @@ -1773,8 +1960,56 @@ void RasterizerSceneGLES2::_setup_light(LightInstance *light, ShadowAtlas *shado } } break; + default: {} + } +} + +void RasterizerSceneGLES2::_setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env) { + + if (p_refprobe1) { + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_USE_BOX_PROJECT, p_refprobe1->probe_ptr->box_projection); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_EXTENTS, p_refprobe1->probe_ptr->extents); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_BOX_OFFSET, p_refprobe1->probe_ptr->origin_offset); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_EXTERIOR, !p_refprobe1->probe_ptr->interior); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_INTENSITY, p_refprobe1->probe_ptr->intensity); + + Color ambient; + if (p_refprobe1->probe_ptr->interior) { + ambient = p_refprobe1->probe_ptr->interior_ambient * p_refprobe1->probe_ptr->interior_ambient_energy; + ambient.a = p_refprobe1->probe_ptr->interior_ambient_probe_contrib; + } else if (p_env) { + ambient = p_env->ambient_color * p_env->ambient_energy; + ambient.a = p_env->ambient_sky_contribution; + } + + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_AMBIENT, ambient); - default: break; + Transform proj = (p_view_transform.inverse() * p_refprobe1->transform).affine_inverse(); + + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE1_LOCAL_MATRIX, proj); + } + + if (p_refprobe2) { + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_USE_BOX_PROJECT, p_refprobe2->probe_ptr->box_projection); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_EXTENTS, p_refprobe2->probe_ptr->extents); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_BOX_OFFSET, p_refprobe2->probe_ptr->origin_offset); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_EXTERIOR, !p_refprobe2->probe_ptr->interior); + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_INTENSITY, p_refprobe2->probe_ptr->intensity); + + Color ambient; + if (p_refprobe2->probe_ptr->interior) { + ambient = p_refprobe2->probe_ptr->interior_ambient * p_refprobe2->probe_ptr->interior_ambient_energy; + ambient.a = p_refprobe2->probe_ptr->interior_ambient_probe_contrib; + } else if (p_env) { + ambient = p_env->ambient_color * p_env->ambient_energy; + ambient.a = p_env->ambient_sky_contribution; + } + + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_AMBIENT, ambient); + + Transform proj = (p_view_transform.inverse() * p_refprobe2->transform).affine_inverse(); + + state.scene_shader.set_uniform(SceneShaderGLES2::REFPROBE2_LOCAL_MATRIX, proj); } } @@ -1782,9 +2017,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); - Vector2 screen_pixel_size; - screen_pixel_size.x = 1.0 / storage->frame.current_rt->width; - screen_pixel_size.y = 1.0 / storage->frame.current_rt->height; + Vector2 screen_pixel_size = state.screen_pixel_size; bool use_radiance_map = false; if (!p_shadow && p_base_env) { @@ -1800,6 +2033,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, RasterizerStorageGLES2::Material *prev_material = NULL; RasterizerStorageGLES2::Geometry *prev_geometry = NULL; RasterizerStorageGLES2::Skeleton *prev_skeleton = NULL; + RasterizerStorageGLES2::GeometryOwner *prev_owner = NULL; Transform view_transform_inverse = p_view_transform.inverse(); CameraMatrix projection_inverse = p_projection.inverse(); @@ -1807,6 +2041,8 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, bool prev_base_pass = false; LightInstance *prev_light = NULL; bool prev_vertex_lit = false; + ReflectionProbeInstance *prev_refprobe_1 = NULL; + ReflectionProbeInstance *prev_refprobe_2 = NULL; int prev_blend_mode = -2; //will always catch the first go @@ -1816,6 +2052,23 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, glDisable(GL_BLEND); } + float fog_max_distance = 0; + bool using_fog = false; + if (p_env && !p_shadow && p_env->fog_enabled && (p_env->fog_depth_enabled || p_env->fog_height_enabled)) { + state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, p_env->fog_depth_enabled); + state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, p_env->fog_height_enabled); + if (p_env->fog_depth_end > 0) { + fog_max_distance = p_env->fog_depth_end; + } else { + fog_max_distance = p_projection.get_z_far(); + } + using_fog = true; + } + + RasterizerStorageGLES2::Texture *prev_lightmap = NULL; + float lightmap_energy = 1.0; + bool prev_use_lightmap_capture = false; + for (int i = 0; i < p_element_count; i++) { RenderList::Element *e = p_elements[i]; @@ -1825,6 +2078,13 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, bool accum_pass = *e->use_accum_ptr; *e->use_accum_ptr = true; //set to accum for next time this is found LightInstance *light = NULL; + ReflectionProbeInstance *refprobe_1 = NULL; + ReflectionProbeInstance *refprobe_2 = NULL; + RasterizerStorageGLES2::Texture *lightmap = NULL; + bool use_lightmap_capture = false; + bool rebind_light = false; + bool rebind_reflection = false; + bool rebind_lightmap = false; if (!p_shadow) { @@ -1860,6 +2120,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, _setup_light_type(light, shadow_atlas); rebind = true; + rebind_light = true; } int blend_mode = p_alpha_pass ? material->shader->spatial.blend_mode : -1; // -1 no blend, no mix @@ -1915,15 +2176,69 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, } //condition to enable vertex lighting on this object - bool vertex_lit = light && (material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading) && !unshaded; + bool vertex_lit = (material->shader->spatial.uses_vertex_lighting || storage->config.force_vertex_shading) && ((!unshaded && light) || using_fog); //fog forces vertex lighting because it still applies even if unshaded or no fog if (vertex_lit != prev_vertex_lit) { state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, vertex_lit); prev_vertex_lit = vertex_lit; } + + if (!unshaded && !accum_pass && e->refprobe_0_index != RenderList::MAX_REFLECTION_PROBES) { + ERR_FAIL_INDEX(e->refprobe_0_index, reflection_probe_count); + refprobe_1 = reflection_probe_instances[e->refprobe_0_index]; + } + if (!unshaded && !accum_pass && e->refprobe_1_index != RenderList::MAX_REFLECTION_PROBES) { + ERR_FAIL_INDEX(e->refprobe_1_index, reflection_probe_count); + refprobe_2 = reflection_probe_instances[e->refprobe_1_index]; + } + + if (refprobe_1 != prev_refprobe_1 || refprobe_2 != prev_refprobe_2) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, refprobe_1 != NULL); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, refprobe_2 != NULL); + if (refprobe_1 != NULL && refprobe_1 != prev_refprobe_1) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 5); + glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_1->cubemap); + } + if (refprobe_2 != NULL && refprobe_2 != prev_refprobe_2) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 6); + glBindTexture(GL_TEXTURE_CUBE_MAP, refprobe_2->cubemap); + } + rebind = true; + rebind_reflection = true; + } + + use_lightmap_capture = !unshaded && !accum_pass && !e->instance->lightmap_capture_data.empty(); + + if (use_lightmap_capture != prev_use_lightmap_capture) { + + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, use_lightmap_capture); + rebind = true; + } + + if (!unshaded && !accum_pass && e->instance->lightmap.is_valid()) { + + lightmap = storage->texture_owner.getornull(e->instance->lightmap); + lightmap_energy = 1.0; + if (lightmap) { + RasterizerStorageGLES2::LightmapCapture *capture = storage->lightmap_capture_data_owner.getornull(e->instance->lightmap_capture->base); + if (capture) { + lightmap_energy = capture->energy; + } + } + } + + if (lightmap != prev_lightmap) { + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, lightmap != NULL); + if (lightmap != NULL) { + glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); + glBindTexture(GL_TEXTURE_2D, lightmap->tex_id); + } + rebind = true; + rebind_lightmap = true; + } } - bool instancing = e->instancing; + bool instancing = e->instance->base_type == VS::INSTANCE_MULTIMESH; if (instancing != prev_instancing) { @@ -1936,7 +2251,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, if (skeleton != prev_skeleton) { if (skeleton) { - state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, skeleton != NULL); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, true); state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, !storage->config.float_texture_supported); } else { state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); @@ -1946,7 +2261,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, rebind = true; } - if (e->geometry != prev_geometry || skeleton != prev_skeleton) { + if (e->owner != prev_owner || e->geometry != prev_geometry || skeleton != prev_skeleton) { _setup_geometry(e, skeleton); } @@ -1955,7 +2270,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, shader_rebind = _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0)); } - if (i == 0 || shader_rebind) { //first time must rebindmakin + if (i == 0 || shader_rebind) { //first time must rebind if (p_shadow) { state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias); @@ -1972,6 +2287,7 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, if (p_env) { state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy); state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution); + state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color); state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, p_env->ambient_energy); @@ -1982,41 +2298,95 @@ void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0); } - if (light) { - _setup_light(light, shadow_atlas, p_view_transform); + //rebind all these + rebind_light = true; + rebind_reflection = true; + rebind_lightmap = true; + + if (using_fog) { + + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_COLOR_BASE, p_env->fog_color); + Color sun_color_amount = p_env->fog_sun_color; + sun_color_amount.a = p_env->fog_sun_amount; + + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_SUN_COLOR_AMOUNT, sun_color_amount); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_TRANSMIT_ENABLED, p_env->fog_transmit_enabled); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_TRANSMIT_CURVE, p_env->fog_transmit_curve); + + if (p_env->fog_depth_enabled) { + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_DEPTH_BEGIN, p_env->fog_depth_begin); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_DEPTH_CURVE, p_env->fog_depth_curve); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_MAX_DISTANCE, fog_max_distance); + } + + if (p_env->fog_height_enabled) { + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MIN, p_env->fog_height_min); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MAX, p_env->fog_height_max); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_MAX, p_env->fog_height_max); + state.scene_shader.set_uniform(SceneShaderGLES2::FOG_HEIGHT_CURVE, p_env->fog_height_curve); + } } } - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, view_transform_inverse); - state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform); + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform); + state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, view_transform_inverse); state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection); state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, projection_inverse); state.scene_shader.set_uniform(SceneShaderGLES2::TIME, storage->frame.time[0]); state.scene_shader.set_uniform(SceneShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size); - state.scene_shader.set_uniform(SceneShaderGLES2::NORMAL_MULT, 1.0); // TODO mirror? + } + + if (rebind_light && light) { + _setup_light(light, shadow_atlas, p_view_transform); + } + + if (rebind_reflection && (refprobe_1 || refprobe_2)) { + _setup_refprobes(refprobe_1, refprobe_2, p_view_transform, p_env); + } + + if (rebind_lightmap && lightmap) { + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_ENERGY, lightmap_energy); } state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform); + if (use_lightmap_capture) { //this is per instance, must be set always if present + glUniform4fv(state.scene_shader.get_uniform_location(SceneShaderGLES2::LIGHTMAP_CAPTURES), 12, (const GLfloat *)e->instance->lightmap_capture_data.ptr()); + state.scene_shader.set_uniform(SceneShaderGLES2::LIGHTMAP_CAPTURE_SKY, false); + } + _render_geometry(e); prev_geometry = e->geometry; + prev_owner = e->owner; prev_material = material; prev_skeleton = skeleton; prev_instancing = instancing; prev_light = light; + prev_refprobe_1 = refprobe_1; + prev_refprobe_2 = refprobe_2; + prev_lightmap = lightmap; + prev_use_lightmap_capture = use_lightmap_capture; } _setup_light_type(NULL, NULL); //clear light stuff + state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, false); state.scene_shader.set_conditional(SceneShaderGLES2::SHADELESS, false); state.scene_shader.set_conditional(SceneShaderGLES2::BASE_PASS, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false); state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false); state.scene_shader.set_conditional(SceneShaderGLES2::USE_VERTEX_LIGHTING, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE1, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_REFLECTION_PROBE2, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP, false); + state.scene_shader.set_conditional(SceneShaderGLES2::USE_LIGHTMAP_CAPTURE, false); + state.scene_shader.set_conditional(SceneShaderGLES2::FOG_DEPTH_ENABLED, false); + state.scene_shader.set_conditional(SceneShaderGLES2::FOG_HEIGHT_ENABLED, false); } void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy) { @@ -2091,13 +2461,20 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C glEnableVertexAttribArray(VS::ARRAY_VERTEX); glEnableVertexAttribArray(VS::ARRAY_TEX_UV); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, asymmetrical); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, !asymmetrical); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, true); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); - storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, true); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false); storage->shaders.copy.bind(); storage->shaders.copy.set_uniform(CopyShaderGLES2::MULTIPLIER, p_energy); + if (asymmetrical) { + // pack the bits we need from our projection matrix + storage->shaders.copy.set_uniform(CopyShaderGLES2::ASYM_PROJ, camera.matrix[2][0], camera.matrix[0][0], camera.matrix[2][1], camera.matrix[1][1]); + ///@TODO I couldn't get mat3 + p_transform.basis to work, that would be better here. + storage->shaders.copy.set_uniform(CopyShaderGLES2::PANO_TRANSFORM, p_transform); + } glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -2105,12 +2482,47 @@ void RasterizerSceneGLES2::_draw_sky(RasterizerStorageGLES2::Sky *p_sky, const C glDisableVertexAttribArray(VS::ARRAY_TEX_UV); glBindBuffer(GL_ARRAY_BUFFER, 0); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_ASYM_PANO, false); + storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false); storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false); } void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) { + GLuint current_fb = 0; + Environment *env = NULL; + + int viewport_width, viewport_height; + bool probe_interior = false; + + if (p_reflection_probe.is_valid()) { + ReflectionProbeInstance *probe = reflection_probe_instance_owner.getornull(p_reflection_probe); + ERR_FAIL_COND(!probe); + state.render_no_shadows = !probe->probe_ptr->enable_shadows; + + if (!probe->probe_ptr->interior) { //use env only if not interior + env = environment_owner.getornull(p_environment); + } + + current_fb = probe->fbo[p_reflection_probe_pass]; + state.screen_pixel_size.x = 1.0 / probe->probe_ptr->resolution; + state.screen_pixel_size.y = 1.0 / probe->probe_ptr->resolution; + + viewport_width = probe->probe_ptr->resolution; + viewport_height = probe->probe_ptr->resolution; + + probe_interior = probe->probe_ptr->interior; + + } else { + state.render_no_shadows = false; + current_fb = storage->frame.current_rt->fbo; + env = environment_owner.getornull(p_environment); + state.screen_pixel_size.x = 1.0 / storage->frame.current_rt->width; + state.screen_pixel_size.y = 1.0 / storage->frame.current_rt->height; + viewport_width = storage->frame.current_rt->width; + viewport_height = storage->frame.current_rt->height; + } //push back the directional lights if (p_light_cull_count) { @@ -2143,10 +2555,22 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const render_light_instance_count = 0; } - glEnable(GL_BLEND); + if (p_reflection_probe_cull_count) { - GLuint current_fb = storage->frame.current_rt->fbo; - Environment *env = environment_owner.getornull(p_environment); + reflection_probe_instances = (ReflectionProbeInstance **)alloca(sizeof(ReflectionProbeInstance *) * p_reflection_probe_cull_count); + reflection_probe_count = p_reflection_probe_cull_count; + for (int i = 0; i < p_reflection_probe_cull_count; i++) { + ReflectionProbeInstance *rpi = reflection_probe_instance_owner.getornull(p_reflection_probe_cull_result[i]); + ERR_CONTINUE(!rpi); + rpi->last_pass = render_pass + 1; //will be incremented later + rpi->index = i; + reflection_probe_instances[i] = rpi; + } + + } else { + reflection_probe_instances = NULL; + reflection_probe_count = 0; + } // render list stuff @@ -2156,15 +2580,37 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const // other stuff glBindFramebuffer(GL_FRAMEBUFFER, current_fb); + glViewport(0, 0, viewport_width, viewport_height); glDepthFunc(GL_LEQUAL); glDepthMask(GL_TRUE); glClearDepth(1.0f); glEnable(GL_DEPTH_TEST); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + // clear color + + Color clear_color(0, 0, 0, 0); - storage->frame.clear_request = false; + if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + clear_color = Color(0, 0, 0, 0); + storage->frame.clear_request = false; + } else if (!env || env->bg_mode == VS::ENV_BG_CLEAR_COLOR || env->bg_mode == VS::ENV_BG_SKY) { + if (storage->frame.clear_request) { + clear_color = storage->frame.clear_request_color.to_linear(); + storage->frame.clear_request = false; + } + } else if (env->bg_mode == VS::ENV_BG_CANVAS || env->bg_mode == VS::ENV_BG_COLOR || env->bg_mode == VS::ENV_BG_COLOR_SKY) { + clear_color = env->bg_color.to_linear(); + storage->frame.clear_request = false; + } else { + storage->frame.clear_request = false; + } + + if (!env || env->bg_mode != VS::ENV_BG_KEEP) { + glClearColor(clear_color.r, clear_color.g, clear_color.b, clear_color.a); + } + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); @@ -2199,6 +2645,10 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const } } + if (probe_interior) { + env_radiance_tex = 0; //do not use radiance texture on interiors + } + // render opaque things first render_list.sort_by_key(false); _render_render_list(render_list.elements, render_list.element_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false); @@ -2212,7 +2662,6 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false); - glDepthMask(GL_FALSE); glDisable(GL_DEPTH_TEST); //#define GLES2_SHADOW_ATLAS_DEBUG_VIEW @@ -2257,6 +2706,8 @@ void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) { + state.render_no_shadows = false; + LightInstance *light_instance = light_instance_owner.getornull(p_light); ERR_FAIL_COND(!light_instance); @@ -2267,7 +2718,6 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ uint32_t y; uint32_t width; uint32_t height; - uint32_t vp_height; float zfar = 0; bool flip_facing = false; @@ -2353,14 +2803,12 @@ void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_ normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult; fbo = directional_shadow.fbo; - vp_height = directional_shadow.size; } else { ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas); ERR_FAIL_COND(!shadow_atlas); ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); fbo = shadow_atlas->fbo; - vp_height = shadow_atlas->size; uint32_t key = shadow_atlas->shadow_owners[p_light]; @@ -2534,6 +2982,44 @@ void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) { } bool RasterizerSceneGLES2::free(RID p_rid) { + + if (light_instance_owner.owns(p_rid)) { + + LightInstance *light_instance = light_instance_owner.getptr(p_rid); + + //remove from shadow atlases.. + for (Set<RID>::Element *E = light_instance->shadow_atlases.front(); E; E = E->next()) { + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(E->get()); + ERR_CONTINUE(!shadow_atlas->shadow_owners.has(p_rid)); + uint32_t key = shadow_atlas->shadow_owners[p_rid]; + uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3; + uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK; + + shadow_atlas->quadrants[q].shadows.write[s].owner = RID(); + shadow_atlas->shadow_owners.erase(p_rid); + } + + light_instance_owner.free(p_rid); + memdelete(light_instance); + + } else if (shadow_atlas_owner.owns(p_rid)) { + + ShadowAtlas *shadow_atlas = shadow_atlas_owner.get(p_rid); + shadow_atlas_set_size(p_rid, 0); + shadow_atlas_owner.free(p_rid); + memdelete(shadow_atlas); + } else if (reflection_probe_instance_owner.owns(p_rid)) { + + ReflectionProbeInstance *reflection_instance = reflection_probe_instance_owner.get(p_rid); + + reflection_probe_release_atlas_index(p_rid); + reflection_probe_instance_owner.free(p_rid); + memdelete(reflection_instance); + + } else { + return false; + } + return true; } @@ -2594,6 +3080,7 @@ void RasterizerSceneGLES2::initialize() { { uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); glGenBuffers(1, &state.immediate_buffer); glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); @@ -2619,7 +3106,7 @@ void RasterizerSceneGLES2::initialize() { glBindTexture(GL_TEXTURE_CUBE_MAP, cube.cubemap); for (int i = 0; i < 6; i++) { - glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, NULL); + glTexImage2D(_cube_side_enum[i], 0, GL_DEPTH_COMPONENT, cube_size, cube_size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL); } glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST); @@ -2669,10 +3156,6 @@ void RasterizerSceneGLES2::initialize() { } shadow_filter_mode = SHADOW_FILTER_NEAREST; - - RenderList::Element e; - e.sort_key = 0; - e.light_type1 = 1; } void RasterizerSceneGLES2::iteration() { diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h index 27cbc35299..ba406183c7 100644 --- a/drivers/gles2/rasterizer_scene_gles2.h +++ b/drivers/gles2/rasterizer_scene_gles2.h @@ -59,6 +59,11 @@ public: SHADOW_FILTER_PCF13, }; + enum { + INSTANCE_ATTRIB_BASE = 8, + INSTANCE_BONE_BASE = 13, + }; + ShadowFilterMode shadow_filter_mode; RID default_material; @@ -204,6 +209,9 @@ public: float dual_parbolloid_direction; float dual_parbolloid_zfar; + bool render_no_shadows; + + Vector2 screen_pixel_size; } state; /* SHADOW ATLAS API */ @@ -287,6 +295,38 @@ public: /* REFLECTION PROBE INSTANCE */ + struct ReflectionProbeInstance : public RID_Data { + + RasterizerStorageGLES2::ReflectionProbe *probe_ptr; + RID probe; + RID self; + RID atlas; + + int reflection_atlas_index; + + int render_step; + int reflection_index; + + GLuint fbo[6]; + GLuint cubemap; + GLuint depth; + + GLuint fbo_blur; + + int current_resolution; + mutable bool dirty; + + uint64_t last_pass; + uint32_t index; + + Transform transform; + }; + + mutable RID_Owner<ReflectionProbeInstance> reflection_probe_instance_owner; + + ReflectionProbeInstance **reflection_probe_instances; + int reflection_probe_count; + virtual RID reflection_probe_instance_create(RID p_probe); virtual void reflection_probe_instance_set_transform(RID p_instance, const Transform &p_transform); virtual void reflection_probe_release_atlas_index(RID p_instance); @@ -313,6 +353,22 @@ public: int canvas_max_layer; + bool fog_enabled; + Color fog_color; + Color fog_sun_color; + float fog_sun_amount; + + bool fog_depth_enabled; + float fog_depth_begin; + float fog_depth_end; + float fog_depth_curve; + bool fog_transmit_enabled; + float fog_transmit_curve; + bool fog_height_enabled; + float fog_height_min; + float fog_height_max; + float fog_height_curve; + Environment() { bg_mode = VS::ENV_BG_CLEAR_COLOR; sky_custom_fov = 0.0; @@ -321,6 +377,25 @@ public: ambient_energy = 1.0; ambient_sky_contribution = 0.0; canvas_max_layer = 0; + + fog_enabled = false; + fog_color = Color(0.5, 0.5, 0.5); + fog_sun_color = Color(0.8, 0.8, 0.0); + fog_sun_amount = 0; + + fog_depth_enabled = true; + + fog_depth_begin = 10; + fog_depth_end = 0; + fog_depth_curve = 1; + + fog_transmit_enabled = true; + fog_transmit_curve = 1; + + fog_height_enabled = false; + fog_height_min = 0; + fog_height_max = 100; + fog_height_curve = 1; } }; @@ -338,7 +413,7 @@ public: virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); - virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale); + virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness); @@ -349,7 +424,7 @@ public: virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp); virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount); - virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve); + virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve); virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve); virtual bool is_environment(RID p_env); @@ -424,6 +499,7 @@ public: enum { MAX_LIGHTS = 255, + MAX_REFLECTION_PROBES = 255, DEFAULT_MAX_ELEMENTS = 65536 }; @@ -587,6 +663,7 @@ public: _FORCE_INLINE_ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton); _FORCE_INLINE_ void _setup_light_type(LightInstance *p_light, ShadowAtlas *shadow_atlas); _FORCE_INLINE_ void _setup_light(LightInstance *p_light, ShadowAtlas *shadow_atlas, const Transform &p_view_transform); + _FORCE_INLINE_ void _setup_refprobes(ReflectionProbeInstance *p_refprobe1, ReflectionProbeInstance *p_refprobe2, const Transform &p_view_transform, Environment *p_env); _FORCE_INLINE_ void _render_geometry(RenderList::Element *p_element); virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass); diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp index b3ce873b65..3beb8eac33 100644 --- a/drivers/gles2/rasterizer_storage_gles2.cpp +++ b/drivers/gles2/rasterizer_storage_gles2.cpp @@ -54,6 +54,8 @@ GLuint RasterizerStorageGLES2::system_fbo = 0; #define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F +#define _DEPTH_COMPONENT24_OES 0x81A6 + void RasterizerStorageGLES2::bind_quad_array() const { glBindBuffer(GL_ARRAY_BUFFER, resources.quadie); glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0); @@ -356,7 +358,6 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_ GLenum type; bool compressed = false; - bool srgb = false; if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) { p_flags &= ~VS::TEXTURE_FLAG_MIPMAPS; // no mipies for video @@ -497,22 +498,6 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p glTexParameterf(texture->target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); } -//set swizle for older format compatibility -#ifdef GLES_OVER_GL - switch (texture->format) { - - case Image::FORMAT_L8: { - - } break; - case Image::FORMAT_LA8: { - - } break; - default: { - - } break; - } -#endif - int mipmaps = ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && img->has_mipmaps()) ? img->get_mipmap_count() + 1 : 1; int w = img->get_width(); @@ -592,7 +577,7 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) PoolVector<uint8_t> data; - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1 ? -1 : 0); + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers PoolVector<uint8_t>::Write wb = data.write(); @@ -628,8 +613,72 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) return Ref<Image>(img); #else - ERR_EXPLAIN("Sorry, It's not possible to obtain images back in OpenGL ES"); - ERR_FAIL_V(Ref<Image>()); + Image::Format real_format; + GLenum gl_format; + GLenum gl_internal_format; + GLenum gl_type; + bool compressed; + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed); + + PoolVector<uint8_t> data; + + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); + + data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers + PoolVector<uint8_t>::Write wb = data.write(); + + GLuint temp_framebuffer; + glGenFramebuffers(1, &temp_framebuffer); + + GLuint temp_color_texture; + glGenTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + + glBindTexture(GL_TEXTURE_2D, temp_color_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1, 1, 1, 1); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + + glViewport(0, 0, texture->alloc_width, texture->alloc_height); + + shaders.copy.bind(); + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + bind_quad_array(); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindBuffer(GL_ARRAY_BUFFER, 0); + + glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); + + glDeleteTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &temp_framebuffer); + + wb = PoolVector<uint8_t>::Write(); + + data.resize(data_size); + + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); + if (!texture->compressed) { + img->convert(real_format); + } + + return Ref<Image>(img); + #endif } @@ -916,26 +965,27 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra // attachements for it, so we can fill them by issuing draw calls. GLuint tmp_fb; - glGenFramebuffers(1, &tmp_fb); - glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); - int size = p_radiance_size; int lod = 0; - shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, texture->target == GL_TEXTURE_2D); - - shaders.cubemap_filter.bind(); - int mipmaps = 6; int mm_level = mipmaps; - GLenum internal_format = GL_RGBA; - GLenum format = GL_RGBA; - GLenum type = GL_UNSIGNED_BYTE; // This is suboptimal... TODO other format for FBO? + GLenum internal_format = GL_RGB; + GLenum format = GL_RGB; + GLenum type = GL_UNSIGNED_BYTE; // Set the initial (empty) mipmaps +#if 1 + //Mobile hardware (PowerVR specially) prefers this approach, the other one kills the game + for (int i = 0; i < 6; i++) { + glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, size, size, 0, format, type, NULL); + } + + glGenerateMipmap(GL_TEXTURE_CUBE_MAP); +#else while (size >= 1) { for (int i = 0; i < 6; i++) { @@ -946,7 +996,14 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra size >>= 1; } +#endif + //framebuffer + glGenFramebuffers(1, &tmp_fb); + glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb); + + shaders.cubemap_filter.set_conditional(CubemapFilterShaderGLES2::USE_SOURCE_PANORAMA, texture->target == GL_TEXTURE_2D); + shaders.cubemap_filter.bind(); lod = 0; mm_level = mipmaps; @@ -965,6 +1022,7 @@ void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_ra shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i); float roughness = mm_level ? lod / (float)(mipmaps - 1) : 1; + roughness = MIN(1.0, roughness); //keep max at 1 shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness); glDrawArrays(GL_TRIANGLE_FAN, 0, 4); @@ -1067,6 +1125,10 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const { p_shader->uniforms.clear(); + if (p_shader->code == String()) { + return; //just invalid, but no error + } + ShaderCompilerGLES2::GeneratedCode gen_code; ShaderCompilerGLES2::IdentifierActions *actions = NULL; @@ -1310,8 +1372,13 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn pi.hint_string = "CubeMap"; } break; - default: { - + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in GLES2 } break; } @@ -1430,8 +1497,9 @@ Variant RasterizerStorageGLES2::material_get_param_default(RID p_material, const if (material->shader) { if (material->shader->uniforms.has(p_param)) { - Vector<ShaderLanguage::ConstantNode::Value> default_value = material->shader->uniforms[p_param].default_value; - return ShaderLanguage::constant_value_to_variant(default_value, material->shader->uniforms[p_param].type); + ShaderLanguage::ShaderNode::Uniform uniform = material->shader->uniforms[p_param]; + Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); } } return Variant(); @@ -1539,7 +1607,7 @@ void RasterizerStorageGLES2::_update_material(Material *p_material) { if (p_material->shader && p_material->shader->mode == VS::SHADER_SPATIAL) { if (p_material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX && - (!p_material->shader->spatial.uses_alpha || (p_material->shader->spatial.uses_alpha && p_material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))) { + (!p_material->shader->spatial.uses_alpha || p_material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) { can_cast_shadow = true; } @@ -1560,7 +1628,7 @@ void RasterizerStorageGLES2::_update_material(Material *p_material) { } for (Map<RasterizerScene::InstanceBase *, int>::Element *E = p_material->instance_owners.front(); E; E = E->next()) { - E->key()->base_material_changed(); + E->key()->base_changed(false, true); } } } @@ -1947,7 +2015,7 @@ void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: } mesh->surfaces.push_back(surface); - mesh->instance_change_notify(); + mesh->instance_change_notify(true, false); info.vertex_mem += surface->total_data_size; } @@ -2017,7 +2085,7 @@ void RasterizerStorageGLES2::mesh_surface_set_material(RID p_mesh, int p_surface _material_add_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]); } - mesh->instance_material_change_notify(); + mesh->instance_change_notify(false, true); } RID RasterizerStorageGLES2::mesh_surface_get_material(RID p_mesh, int p_surface) const { @@ -2125,13 +2193,11 @@ void RasterizerStorageGLES2::mesh_remove_surface(RID p_mesh, int p_surface) { info.vertex_mem -= surface->total_data_size; - mesh->instance_material_change_notify(); - memdelete(surface); mesh->surfaces.remove(p_surface); - mesh->instance_change_notify(); + mesh->instance_change_notify(true, true); } int RasterizerStorageGLES2::mesh_get_surface_count(RID p_mesh) const { @@ -2636,10 +2702,10 @@ void RasterizerStorageGLES2::update_dirty_multimeshes() { if (multimesh->mesh.is_valid()) { mesh_aabb = mesh_get_aabb(multimesh->mesh, RID()); - } else { - mesh_aabb.size += Vector3(0.001, 0.001, 0.001); } + mesh_aabb.size += Vector3(0.001, 0.001, 0.001); //in case mesh is empty in one of the sides + int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats; int count = multimesh->data.size(); float *data = multimesh->data.ptrw(); @@ -2705,7 +2771,7 @@ void RasterizerStorageGLES2::update_dirty_multimeshes() { multimesh->dirty_aabb = false; multimesh->dirty_data = false; - multimesh->instance_change_notify(); + multimesh->instance_change_notify(true, false); multimesh_update_list.remove(multimesh_update_list.first()); } @@ -2810,7 +2876,7 @@ void RasterizerStorageGLES2::immediate_end(RID p_immediate) { ERR_FAIL_COND(!im->building); im->building = false; - im->instance_change_notify(); + im->instance_change_notify(true, false); } void RasterizerStorageGLES2::immediate_clear(RID p_immediate) { @@ -2819,7 +2885,7 @@ void RasterizerStorageGLES2::immediate_clear(RID p_immediate) { ERR_FAIL_COND(im->building); im->chunks.clear(); - im->instance_change_notify(); + im->instance_change_notify(true, false); } AABB RasterizerStorageGLES2::immediate_get_aabb(RID p_immediate) const { @@ -2833,7 +2899,7 @@ void RasterizerStorageGLES2::immediate_set_material(RID p_immediate, RID p_mater ERR_FAIL_COND(!im); im->material = p_material; - im->instance_material_change_notify(); + im->instance_change_notify(false, true); } RID RasterizerStorageGLES2::immediate_get_material(RID p_immediate) const { @@ -3044,7 +3110,7 @@ void RasterizerStorageGLES2::update_dirty_skeletons() { } for (Set<RasterizerScene::InstanceBase *>::Element *E = skeleton->instances.front(); E; E = E->next()) { - E->get()->base_changed(); + E->get()->base_changed(true, false); } skeleton_update_list.remove(skeleton_update_list.first()); @@ -3109,8 +3175,9 @@ void RasterizerStorageGLES2::light_set_param(RID p_light, VS::LightParam p_param case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS: case VS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } break; + default: {} } light->param[p_param] = p_value; @@ -3123,7 +3190,7 @@ void RasterizerStorageGLES2::light_set_shadow(RID p_light, bool p_enabled) { light->shadow = p_enabled; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_set_shadow_color(RID p_light, const Color &p_color) { @@ -3154,7 +3221,7 @@ void RasterizerStorageGLES2::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->cull_mask = p_mask; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { @@ -3162,6 +3229,9 @@ void RasterizerStorageGLES2::light_set_reverse_cull_face_mode(RID p_light, bool ERR_FAIL_COND(!light); light->reverse_cull = p_enabled; + + light->version++; + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) { @@ -3171,7 +3241,7 @@ void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOm light->omni_shadow_mode = p_mode; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } VS::LightOmniShadowMode RasterizerStorageGLES2::light_omni_get_shadow_mode(RID p_light) { @@ -3188,7 +3258,7 @@ void RasterizerStorageGLES2::light_omni_set_shadow_detail(RID p_light, VS::Light light->omni_shadow_detail = p_detail; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) { @@ -3198,7 +3268,7 @@ void RasterizerStorageGLES2::light_directional_set_shadow_mode(RID p_light, VS:: light->directional_shadow_mode = p_mode; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES2::light_directional_set_blend_splits(RID p_light, bool p_enable) { @@ -3208,7 +3278,7 @@ void RasterizerStorageGLES2::light_directional_set_blend_splits(RID p_light, boo light->directional_blend_splits = p_enable; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } bool RasterizerStorageGLES2::light_directional_get_blend_splits(RID p_light) const { @@ -3302,69 +3372,194 @@ AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const { /* PROBE API */ RID RasterizerStorageGLES2::reflection_probe_create() { - return RID(); + + ReflectionProbe *reflection_probe = memnew(ReflectionProbe); + + reflection_probe->intensity = 1.0; + reflection_probe->interior_ambient = Color(); + reflection_probe->interior_ambient_energy = 1.0; + reflection_probe->max_distance = 0; + reflection_probe->extents = Vector3(1, 1, 1); + reflection_probe->origin_offset = Vector3(0, 0, 0); + reflection_probe->interior = false; + reflection_probe->box_projection = false; + reflection_probe->enable_shadows = false; + reflection_probe->cull_mask = (1 << 20) - 1; + reflection_probe->update_mode = VS::REFLECTION_PROBE_UPDATE_ONCE; + reflection_probe->resolution = 128; + + return reflection_probe_owner.make_rid(reflection_probe); } void RasterizerStorageGLES2::reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->update_mode = p_mode; + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES2::reflection_probe_set_intensity(RID p_probe, float p_intensity) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->intensity = p_intensity; } void RasterizerStorageGLES2::reflection_probe_set_interior_ambient(RID p_probe, const Color &p_ambient) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient = p_ambient; } void RasterizerStorageGLES2::reflection_probe_set_interior_ambient_energy(RID p_probe, float p_energy) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_energy = p_energy; } void RasterizerStorageGLES2::reflection_probe_set_interior_ambient_probe_contribution(RID p_probe, float p_contrib) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior_ambient_probe_contrib = p_contrib; } void RasterizerStorageGLES2::reflection_probe_set_max_distance(RID p_probe, float p_distance) { -} -void RasterizerStorageGLES2::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->max_distance = p_distance; + reflection_probe->instance_change_notify(true, false); } +void RasterizerStorageGLES2::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + reflection_probe->extents = p_extents; + reflection_probe->instance_change_notify(true, false); +} void RasterizerStorageGLES2::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->origin_offset = p_offset; + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES2::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { -} + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->interior = p_enable; +} void RasterizerStorageGLES2::reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->box_projection = p_enable; } void RasterizerStorageGLES2::reflection_probe_set_enable_shadows(RID p_probe, bool p_enable) { -} + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->enable_shadows = p_enable; + reflection_probe->instance_change_notify(true, false); +} void RasterizerStorageGLES2::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->cull_mask = p_layers; + reflection_probe->instance_change_notify(true, false); +} + +void RasterizerStorageGLES2::reflection_probe_set_resolution(RID p_probe, int p_resolution) { + + ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND(!reflection_probe); + + reflection_probe->resolution = p_resolution; } AABB RasterizerStorageGLES2::reflection_probe_get_aabb(RID p_probe) const { - return AABB(); + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, AABB()); + + AABB aabb; + aabb.position = -reflection_probe->extents; + aabb.size = reflection_probe->extents * 2.0; + + return aabb; } VS::ReflectionProbeUpdateMode RasterizerStorageGLES2::reflection_probe_get_update_mode(RID p_probe) const { - return VS::REFLECTION_PROBE_UPDATE_ALWAYS; + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, VS::REFLECTION_PROBE_UPDATE_ALWAYS); + + return reflection_probe->update_mode; } uint32_t RasterizerStorageGLES2::reflection_probe_get_cull_mask(RID p_probe) const { - return 0; + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->cull_mask; } Vector3 RasterizerStorageGLES2::reflection_probe_get_extents(RID p_probe) const { - return Vector3(); + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, Vector3()); + + return reflection_probe->extents; } Vector3 RasterizerStorageGLES2::reflection_probe_get_origin_offset(RID p_probe) const { - return Vector3(); + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, Vector3()); + + return reflection_probe->origin_offset; } bool RasterizerStorageGLES2::reflection_probe_renders_shadows(RID p_probe) const { - return false; + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, false); + + return reflection_probe->enable_shadows; } float RasterizerStorageGLES2::reflection_probe_get_origin_max_distance(RID p_probe) const { - return 0; + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->max_distance; +} + +int RasterizerStorageGLES2::reflection_probe_get_resolution(RID p_probe) const { + + const ReflectionProbe *reflection_probe = reflection_probe_owner.getornull(p_probe); + ERR_FAIL_COND_V(!reflection_probe, 0); + + return reflection_probe->resolution; } RID RasterizerStorageGLES2::gi_probe_create() { @@ -3465,46 +3660,100 @@ void RasterizerStorageGLES2::gi_probe_dynamic_data_update(RID p_gi_probe_data, i /////// RID RasterizerStorageGLES2::lightmap_capture_create() { - return RID(); + + LightmapCapture *capture = memnew(LightmapCapture); + return lightmap_capture_data_owner.make_rid(capture); } void RasterizerStorageGLES2::lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds) { -} -AABB RasterizerStorageGLES2::lightmap_capture_get_bounds(RID p_capture) const { - return AABB(); + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->bounds = p_bounds; + capture->instance_change_notify(true, false); } +AABB RasterizerStorageGLES2::lightmap_capture_get_bounds(RID p_capture) const { -void RasterizerStorageGLES2::lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) { + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, AABB()); + return capture->bounds; } +void RasterizerStorageGLES2::lightmap_capture_set_octree(RID p_capture, const PoolVector<uint8_t> &p_octree) { + + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + ERR_FAIL_COND(p_octree.size() == 0 || (p_octree.size() % sizeof(LightmapCaptureOctree)) != 0); + + capture->octree.resize(p_octree.size() / sizeof(LightmapCaptureOctree)); + if (p_octree.size()) { + PoolVector<LightmapCaptureOctree>::Write w = capture->octree.write(); + PoolVector<uint8_t>::Read r = p_octree.read(); + copymem(w.ptr(), r.ptr(), p_octree.size()); + } + capture->instance_change_notify(true, false); +} PoolVector<uint8_t> RasterizerStorageGLES2::lightmap_capture_get_octree(RID p_capture) const { - return PoolVector<uint8_t>(); + + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, PoolVector<uint8_t>()); + + if (capture->octree.size() == 0) + return PoolVector<uint8_t>(); + + PoolVector<uint8_t> ret; + ret.resize(capture->octree.size() * sizeof(LightmapCaptureOctree)); + { + PoolVector<LightmapCaptureOctree>::Read r = capture->octree.read(); + PoolVector<uint8_t>::Write w = ret.write(); + copymem(w.ptr(), r.ptr(), ret.size()); + } + + return ret; } void RasterizerStorageGLES2::lightmap_capture_set_octree_cell_transform(RID p_capture, const Transform &p_xform) { + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->cell_xform = p_xform; } Transform RasterizerStorageGLES2::lightmap_capture_get_octree_cell_transform(RID p_capture) const { - return Transform(); + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, Transform()); + return capture->cell_xform; } void RasterizerStorageGLES2::lightmap_capture_set_octree_cell_subdiv(RID p_capture, int p_subdiv) { + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->cell_subdiv = p_subdiv; } int RasterizerStorageGLES2::lightmap_capture_get_octree_cell_subdiv(RID p_capture) const { - return 0; + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, 0); + return capture->cell_subdiv; } void RasterizerStorageGLES2::lightmap_capture_set_energy(RID p_capture, float p_energy) { + + LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND(!capture); + capture->energy = p_energy; } float RasterizerStorageGLES2::lightmap_capture_get_energy(RID p_capture) const { - return 0.0; + + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, 0); + return capture->energy; } const PoolVector<RasterizerStorage::LightmapCaptureOctree> *RasterizerStorageGLES2::lightmap_capture_get_octree_ptr(RID p_capture) const { - return NULL; + const LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); + ERR_FAIL_COND_V(!capture, NULL); + return &capture->octree; } /////// @@ -3593,18 +3842,122 @@ RID RasterizerStorageGLES2::particles_get_draw_pass_mesh(RID p_particles, int p_ void RasterizerStorageGLES2::update_particles() { } +bool RasterizerStorageGLES2::particles_is_inactive(RID p_particles) const { + return true; +} + //////// void RasterizerStorageGLES2::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + + skeleton->instances.insert(p_instance); } void RasterizerStorageGLES2::instance_remove_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { + + Skeleton *skeleton = skeleton_owner.getornull(p_skeleton); + ERR_FAIL_COND(!skeleton); + + skeleton->instances.erase(p_instance); } void RasterizerStorageGLES2::instance_add_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { + + Instantiable *inst = NULL; + switch (p_instance->base_type) { + case VS::INSTANCE_MESH: { + inst = mesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_MULTIMESH: { + inst = multimesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_IMMEDIATE: { + inst = immediate_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + /*case VS::INSTANCE_PARTICLES: { + inst = particles_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break;*/ + case VS::INSTANCE_REFLECTION_PROBE: { + inst = reflection_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_LIGHT: { + inst = light_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + /*case VS::INSTANCE_GI_PROBE: { + inst = gi_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break;*/ + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + inst = lightmap_capture_data_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + default: { + if (!inst) { + ERR_FAIL(); + } + } + } + + inst->instance_list.add(&p_instance->dependency_item); } void RasterizerStorageGLES2::instance_remove_dependency(RID p_base, RasterizerScene::InstanceBase *p_instance) { + + Instantiable *inst = NULL; + + switch (p_instance->base_type) { + case VS::INSTANCE_MESH: { + inst = mesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_MULTIMESH: { + inst = multimesh_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_IMMEDIATE: { + inst = immediate_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + /*case VS::INSTANCE_PARTICLES: { + inst = particles_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break;*/ + case VS::INSTANCE_REFLECTION_PROBE: { + inst = reflection_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + case VS::INSTANCE_LIGHT: { + inst = light_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + /*case VS::INSTANCE_GI_PROBE: { + inst = gi_probe_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; */ + case VS::INSTANCE_LIGHTMAP_CAPTURE: { + inst = lightmap_capture_data_owner.getornull(p_base); + ERR_FAIL_COND(!inst); + } break; + default: { + + if (!inst) { + ERR_FAIL(); + } + } + } + + ERR_FAIL_COND(!inst); + + inst->instance_list.remove(&p_instance->dependency_item); } /* RENDER TARGET */ @@ -3646,7 +3999,7 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) { glGenRenderbuffers(1, &rt->depth); glBindRenderbuffer(GL_RENDERBUFFER, rt->depth); - glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16, rt->width, rt->height); + glRenderbufferStorage(GL_RENDERBUFFER, _DEPTH_COMPONENT24_OES, rt->width, rt->height); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, rt->depth); GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); @@ -3862,6 +4215,10 @@ VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const { return VS::INSTANCE_MULTIMESH; } else if (immediate_owner.owns(p_rid)) { return VS::INSTANCE_IMMEDIATE; + } else if (reflection_probe_owner.owns(p_rid)) { + return VS::INSTANCE_REFLECTION_PROBE; + } else if (lightmap_capture_data_owner.owns(p_rid)) { + return VS::INSTANCE_LIGHTMAP_CAPTURE; } else { return VS::INSTANCE_NONE; } @@ -4039,6 +4396,25 @@ bool RasterizerStorageGLES2::free(RID p_rid) { memdelete(light); return true; + } else if (reflection_probe_owner.owns(p_rid)) { + + // delete the texture + ReflectionProbe *reflection_probe = reflection_probe_owner.get(p_rid); + reflection_probe->instance_remove_deps(); + + reflection_probe_owner.free(p_rid); + memdelete(reflection_probe); + + return true; + } else if (lightmap_capture_data_owner.owns(p_rid)) { + + // delete the texture + LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid); + lightmap_capture->instance_remove_deps(); + + lightmap_capture_data_owner.free(p_rid); + memdelete(lightmap_capture); + return true; } else { return false; } @@ -4089,16 +4465,17 @@ void RasterizerStorageGLES2::initialize() { } } + config.keep_original_textures = false; config.shrink_textures_x2 = false; - config.float_texture_supported = config.extensions.find("GL_ARB_texture_float") != NULL || config.extensions.find("GL_OES_texture_float") != NULL; - config.s3tc_supported = config.extensions.find("GL_EXT_texture_compression_s3tc") != NULL; - config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture") != NULL; + + config.float_texture_supported = config.extensions.has("GL_ARB_texture_float") || config.extensions.has("GL_OES_texture_float"); + config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_s3tc"); + config.etc1_supported = config.extensions.has("GL_OES_compressed_ETC1_RGB8_texture"); frame.count = 0; frame.delta = 0; frame.current_rt = NULL; frame.clear_request = false; - // config.keep_original_textures = false; glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units); glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size); @@ -4201,13 +4578,13 @@ void RasterizerStorageGLES2::initialize() { // radical inverse vdc cache texture // used for cubemap filtering - if (config.float_texture_supported) { + if (true /*||config.float_texture_supported*/) { //uint8 is similar and works everywhere glGenTextures(1, &resources.radical_inverse_vdc_cache_tex); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, resources.radical_inverse_vdc_cache_tex); - float radical_inverse[512]; + uint8_t radical_inverse[512]; for (uint32_t i = 0; i < 512; i++) { uint32_t bits = i; @@ -4219,20 +4596,24 @@ void RasterizerStorageGLES2::initialize() { bits = ((bits & 0x00FF00FF) << 8) | ((bits & 0xFF00FF00) >> 8); float value = float(bits) * 2.3283064365386963e-10; - - radical_inverse[i] = value; + radical_inverse[i] = uint8_t(CLAMP(value * 255.0, 0, 255)); } - glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_FLOAT, radical_inverse); + glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, radical_inverse); glBindTexture(GL_TEXTURE_2D, 0); } #ifdef GLES_OVER_GL + //this needs to be enabled manually in OpenGL 2.1 + glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS); + glEnable(GL_POINT_SPRITE); + glEnable(GL_VERTEX_PROGRAM_POINT_SIZE); #endif config.force_vertex_shading = GLOBAL_GET("rendering/quality/shading/force_vertex_shading"); + config.use_fast_texture_filter = GLOBAL_GET("rendering/quality/filters/use_nearest_mipmap_filter"); } void RasterizerStorageGLES2::finalize() { @@ -4247,6 +4628,7 @@ void RasterizerStorageGLES2::update_dirty_resources() { update_dirty_shaders(); update_dirty_materials(); update_dirty_skeletons(); + update_dirty_multimeshes(); } RasterizerStorageGLES2::RasterizerStorageGLES2() { diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h index e6708914ec..5bdc65a0b5 100644 --- a/drivers/gles2/rasterizer_storage_gles2.h +++ b/drivers/gles2/rasterizer_storage_gles2.h @@ -43,7 +43,6 @@ /* #include "shaders/blend_shape.glsl.gen.h" #include "shaders/canvas.glsl.gen.h" -#include "shaders/copy.glsl.gen.h" #include "shaders/particles.glsl.gen.h" */ @@ -61,20 +60,12 @@ public: bool shrink_textures_x2; bool use_fast_texture_filter; - // bool use_anisotropic_filter; - - bool hdr_supported; - - bool use_rgba_2d_shadows; - - // float anisotropic_level; int max_texture_image_units; int max_texture_size; - bool generate_wireframes; - - bool use_texture_array_environment; + // TODO implement wireframe in GLES2 + // bool generate_wireframes; Set<String> extensions; @@ -84,7 +75,6 @@ public: bool keep_original_textures; - bool no_depth_prepass; bool force_vertex_shading; } config; @@ -157,23 +147,15 @@ public: //////////////////////////////////DATA/////////////////////////////////////////////////// ///////////////////////////////////////////////////////////////////////////////////////// - struct Instanciable : public RID_Data { + struct Instantiable : public RID_Data { SelfList<RasterizerScene::InstanceBase>::List instance_list; - _FORCE_INLINE_ void instance_change_notify() { - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); + _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { - while (instances) { - instances->self()->base_changed(); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_material_change_notify() { SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - instances->self()->base_material_changed(); + + instances->self()->base_changed(p_aabb, p_materials); instances = instances->next(); } } @@ -187,15 +169,15 @@ public: } } - Instanciable() {} + Instantiable() {} - virtual ~Instanciable() {} + virtual ~Instantiable() {} }; - struct GeometryOwner : public Instanciable { + struct GeometryOwner : public Instantiable { }; - struct Geometry : public Instanciable { + struct Geometry : public Instantiable { enum Type { GEOMETRY_INVALID, @@ -273,31 +255,28 @@ public: void *detect_normal_ud; Texture() { - flags = 0; - width = 0; - height = 0; alloc_width = 0; alloc_height = 0; - format = Image::FORMAT_L8; - target = 0; - data_size = 0; - total_data_size = 0; + stored_cube_sides = 0; ignore_mipmaps = false; - - compressed = false; - - active = false; - + render_target = NULL; + flags = width = height = 0; tex_id = 0; - - stored_cube_sides = 0; - + data_size = 0; + format = Image::FORMAT_L8; + active = false; + compressed = false; + total_data_size = 0; + mipmaps = 0; + detect_3d = NULL; + detect_3d_ud = NULL; + detect_srgb = NULL; + detect_srgb_ud = NULL; + detect_normal = NULL; + detect_normal_ud = NULL; proxy = NULL; - - render_target = NULL; - redraw_if_visible = false; } @@ -430,6 +409,7 @@ public: int light_mode; */ + bool uses_screen_texture; bool uses_screen_uv; bool uses_time; @@ -673,7 +653,7 @@ public: SelfList<MultiMesh> *mm = multimeshes.first(); while (mm) { - mm->self()->instance_material_change_notify(); + mm->self()->instance_change_notify(false, true); mm = mm->next(); } } @@ -893,7 +873,7 @@ public: /* Light API */ - struct Light : Instanciable { + struct Light : Instantiable { VS::LightType type; float param[VS::LIGHT_PARAM_MAX]; @@ -955,6 +935,26 @@ public: virtual uint64_t light_get_version(RID p_light) const; /* PROBE API */ + + struct ReflectionProbe : Instantiable { + + VS::ReflectionProbeUpdateMode update_mode; + float intensity; + Color interior_ambient; + float interior_ambient_energy; + float interior_ambient_probe_contrib; + float max_distance; + Vector3 extents; + Vector3 origin_offset; + bool interior; + bool box_projection; + bool enable_shadows; + uint32_t cull_mask; + int resolution; + }; + + mutable RID_Owner<ReflectionProbe> reflection_probe_owner; + virtual RID reflection_probe_create(); virtual void reflection_probe_set_update_mode(RID p_probe, VS::ReflectionProbeUpdateMode p_mode); @@ -969,11 +969,14 @@ public: virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); + virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); virtual AABB reflection_probe_get_aabb(RID p_probe) const; virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; virtual uint32_t reflection_probe_get_cull_mask(RID p_probe) const; + virtual int reflection_probe_get_resolution(RID p_probe) const; + virtual Vector3 reflection_probe_get_extents(RID p_probe) const; virtual Vector3 reflection_probe_get_origin_offset(RID p_probe) const; virtual float reflection_probe_get_origin_max_distance(RID p_probe) const; @@ -1023,6 +1026,21 @@ public: /* LIGHTMAP */ + struct LightmapCapture : public Instantiable { + + PoolVector<LightmapCaptureOctree> octree; + AABB bounds; + Transform cell_xform; + int cell_subdiv; + float energy; + LightmapCapture() { + energy = 1.0; + cell_subdiv = 1; + } + }; + + mutable RID_Owner<LightmapCapture> lightmap_capture_data_owner; + virtual RID lightmap_capture_create(); virtual void lightmap_capture_set_bounds(RID p_capture, const AABB &p_bounds); virtual AABB lightmap_capture_get_bounds(RID p_capture) const; @@ -1072,6 +1090,8 @@ public: virtual int particles_get_draw_passes(RID p_particles) const; virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const; + virtual bool particles_is_inactive(RID p_particles) const; + /* INSTANCE */ virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp index bedcfbb798..45b0d695a3 100644 --- a/drivers/gles2/shader_compiler_gles2.cpp +++ b/drivers/gles2/shader_compiler_gles2.cpp @@ -80,19 +80,17 @@ static String _opstr(SL::Operator p_op) { static String _mkid(const String &p_id) { - StringBuffer<> id; - id += "m_"; - id += p_id; - - return id.as_string(); + String id = "m_" + p_id; + return id.replace("__", "_dus_"); //doubleunderscore is reserverd in glsl } static String f2sp0(float p_float) { - if (int(p_float) == p_float) - return itos(p_float) + ".0"; - else - return rtoss(p_float); + String num = rtoss(p_float); + if (num.find(".") == -1 && num.find("e") == -1) { + num += ".0"; + } + return num; } static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { @@ -364,6 +362,7 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener for (int i = 0; i < snode->functions.size(); i++) { SL::FunctionNode *fnode = snode->functions[i].function; + current_func_name = fnode->name; function_code[fnode->name] = _dump_node_code(fnode->body, 1, r_gen_code, p_actions, p_default_actions, p_assigning); } @@ -643,11 +642,11 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener case SL::OP_MOD: { - code += "mod("; + code += "mod(float("; code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ", "; + code += "), float("; code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning); - code += ")"; + code += "))"; } break; default: { @@ -815,8 +814,8 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { /** SPATIAL SHADER **/ actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform"; - actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_matrix"; - actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_inverse_matrix"; + actions[VS::SHADER_SPATIAL].renames["INV_CAMERA_MATRIX"] = "camera_inverse_matrix"; + actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_matrix"; actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix"; actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "projection_inverse_matrix"; actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview"; @@ -932,7 +931,7 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() { actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color"; actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz"; actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass"; - actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "active"; + actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active"; actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart"; actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom"; actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform"; diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp index 650e8f7c42..84bd413abb 100644 --- a/drivers/gles2/shader_gles2.cpp +++ b/drivers/gles2/shader_gles2.cpp @@ -99,7 +99,7 @@ void ShaderGLES2::bind_uniforms() { const Map<uint32_t, CameraMatrix>::Element *C = uniform_cameras.front(); while (C) { - int idx = E->key(); + int idx = C->key(); int location = version->uniform_location[idx]; if (location < 0) { @@ -196,6 +196,12 @@ static void _display_error_with_code(const String &p_error, const Vector<const c ERR_PRINTS(p_error); } +static String _mkid(const String &p_id) { + + String id = "m_" + p_id; + return id.replace("__", "_dus_"); //doubleunderscore is reserverd in glsl +} + ShaderGLES2::Version *ShaderGLES2::get_current_version() { Version *_v = version_map.getptr(conditional_version); @@ -492,15 +498,15 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() { if (cc) { // uniforms for (int i = 0; i < cc->custom_uniforms.size(); i++) { - StringName native_uniform_name = "m_" + cc->custom_uniforms[i]; - GLint location = glGetUniformLocation(v.id, ((String)native_uniform_name).ascii().get_data()); + String native_uniform_name = _mkid(cc->custom_uniforms[i]); + GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); v.custom_uniform_locations[cc->custom_uniforms[i]] = location; } // textures for (int i = 0; i < cc->texture_uniforms.size(); i++) { - StringName native_uniform_name = "m_" + cc->texture_uniforms[i]; - GLint location = glGetUniformLocation(v.id, ((String)native_uniform_name).ascii().get_data()); + String native_uniform_name = _mkid(cc->texture_uniforms[i]); + GLint location = glGetUniformLocation(v.id, (native_uniform_name).ascii().get_data()); v.custom_uniform_locations[cc->texture_uniforms[i]] = location; } } @@ -690,11 +696,6 @@ void ShaderGLES2::use_material(void *p_material) { Version *v = version_map.getptr(conditional_version); - CustomCode *cc = NULL; - if (v) { - cc = custom_code_map.getptr(v->code_version); - } - // bind uniforms for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) { @@ -982,7 +983,7 @@ void ShaderGLES2::use_material(void *p_material) { value.second.resize(default_arg_size); - for (int i = 0; i < default_arg_size; i++) { + for (size_t i = 0; i < default_arg_size; i++) { if (is_float) { value.second.write[i].real = 0.0; } else { @@ -992,8 +993,6 @@ void ShaderGLES2::use_material(void *p_material) { } } - // GLint location = get_uniform_location(E->key()); - GLint location; if (v->custom_uniform_locations.has(E->key())) { location = v->custom_uniform_locations[E->key()]; @@ -1013,8 +1012,6 @@ void ShaderGLES2::use_material(void *p_material) { int tc = material->textures.size(); Pair<StringName, RID> *textures = material->textures.ptrw(); - ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = material->shader->texture_hints.ptrw(); - for (int i = 0; i < tc; i++) { Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > value; diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h index 78e1962f80..9160a7c265 100644 --- a/drivers/gles2/shader_gles2.h +++ b/drivers/gles2/shader_gles2.h @@ -335,6 +335,19 @@ public: case ShaderLanguage::TYPE_SAMPLERCUBE: { } break; + + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: + case ShaderLanguage::TYPE_SAMPLER3D: + case ShaderLanguage::TYPE_ISAMPLER3D: + case ShaderLanguage::TYPE_USAMPLER3D: { + // Not implemented in GLES2 + } break; + + case ShaderLanguage::TYPE_VOID: { + // Nothing to do? + } break; } } diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub index acb93fff8f..d959d3f740 100644 --- a/drivers/gles2/shaders/SCsub +++ b/drivers/gles2/shaders/SCsub @@ -20,3 +20,4 @@ if 'GLES2_GLSL' in env['BUILDERS']: # env.GLES2_GLSL('exposure.glsl'); # env.GLES2_GLSL('tonemap.glsl'); # env.GLES2_GLSL('particles.glsl'); + env.GLES2_GLSL('lens_distorted.glsl'); diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl index ba69ca9b6e..79d4eb2243 100644 --- a/drivers/gles2/shaders/canvas.glsl +++ b/drivers/gles2/shaders/canvas.glsl @@ -89,9 +89,18 @@ VERTEX_SHADER_CODE /* clang-format on */ } +#if !defined(SKIP_TRANSFORM_USED) + outvec = extra_matrix * outvec; + outvec = modelview_matrix * outvec; +#endif + color_interp = color; - gl_Position = projection_matrix * modelview_matrix * outvec; +#ifdef USE_PIXEL_SNAP + outvec.xy = floor(outvec + 0.5).xy; +#endif + + gl_Position = projection_matrix * outvec; } /* clang-format off */ @@ -139,7 +148,10 @@ void main() { vec4 color = color_interp; +#if !defined(COLOR_USED) + //default behavior, texture by color color *= texture2D(color_texture, uv_interp); +#endif #ifdef SCREEN_UV_USED vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl index 16bbde196d..0b8da4f875 100644 --- a/drivers/gles2/shaders/copy.glsl +++ b/drivers/gles2/shaders/copy.glsl @@ -35,6 +35,8 @@ void main() { #if defined(USE_CUBEMAP) || defined(USE_PANORAMA) cube_interp = cube_in; +#elif defined(USE_ASYM_PANO) + uv_interp = vertex_attrib.xy; #else uv_interp = uv_in; #endif @@ -68,6 +70,11 @@ varying vec2 uv_interp; #endif /* clang-format on */ +#ifdef USE_ASYM_PANO +uniform highp mat4 pano_transform; +uniform highp vec4 asym_proj; +#endif + #ifdef USE_CUBEMAP uniform samplerCube source_cube; // texunit:0 #else @@ -108,6 +115,21 @@ void main() { vec4 color = texturePanorama(source, normalize(cube_interp)); +#elif defined(USE_ASYM_PANO) + + // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result. + // Note that we're ignoring the x-offset for IPD, with Z sufficiently in the distance it becomes neglectible, as a result we could probably just set cube_normal.z to -1. + // The Matrix[2][0] (= asym_proj.x) and Matrix[2][1] (= asym_proj.z) values are what provide the right shift in the image. + + vec3 cube_normal; + cube_normal.z = -1000000.0; + cube_normal.x = (cube_normal.z * (-uv_interp.x - asym_proj.x)) / asym_proj.y; + cube_normal.y = (cube_normal.z * (-uv_interp.y - asym_proj.z)) / asym_proj.a; + cube_normal = mat3(pano_transform) * cube_normal; + cube_normal.z = -cube_normal.z; + + vec4 color = texturePanorama(source, normalize(cube_normal.xyz)); + #elif defined(USE_CUBEMAP) vec4 color = textureCube(source_cube, normalize(cube_interp)); #else diff --git a/drivers/gles2/shaders/cubemap_filter.glsl b/drivers/gles2/shaders/cubemap_filter.glsl index 2a1ad8d8f2..b1553c7cd5 100644 --- a/drivers/gles2/shaders/cubemap_filter.glsl +++ b/drivers/gles2/shaders/cubemap_filter.glsl @@ -167,18 +167,21 @@ void main() { vec3 H = ImportanceSampleGGX(xi, roughness, N); vec3 V = N; - vec3 L = normalize(2.0 * dot(V, H) * H - V); + vec3 L = (2.0 * dot(V, H) * H - V); float NdotL = clamp(dot(N, L), 0.0, 1.0); if (NdotL > 0.0) { #ifdef USE_SOURCE_PANORAMA - sum.rgb += texturePanorama(source_panorama, L).rgb * NdotL; + vec3 val = texturePanorama(source_panorama, L).rgb; #else - L.y = -L.y; - sum.rgb += textureCubeLod(source_cube, L, 0.0).rgb * NdotL; + vec3 val = textureCubeLod(source_cube, L, 0.0).rgb; #endif + //mix using Linear, to approximate high end back-end + val = mix(pow((val + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), val * (1.0 / 12.92), vec3(lessThan(val, vec3(0.04045)))); + + sum.rgb += val * NdotL; sum.a += NdotL; } @@ -186,5 +189,8 @@ void main() { sum /= sum.a; + vec3 a = vec3(0.055); + sum.rgb = mix((vec3(1.0) + a) * pow(sum.rgb, vec3(1.0 / 2.4)) - a, 12.92 * sum.rgb, vec3(lessThan(sum.rgb, vec3(0.0031308)))); + gl_FragColor = vec4(sum.rgb, 1.0); } diff --git a/drivers/gles2/shaders/lens_distorted.glsl b/drivers/gles2/shaders/lens_distorted.glsl new file mode 100644 index 0000000000..d541db9bf9 --- /dev/null +++ b/drivers/gles2/shaders/lens_distorted.glsl @@ -0,0 +1,62 @@ +/* clang-format off */ +[vertex] + +attribute highp vec2 vertex; // attrib:0 +/* clang-format on */ + +uniform vec2 offset; +uniform vec2 scale; + +varying vec2 uv_interp; + +void main() { + + uv_interp = vertex.xy * 2.0 - 1.0; + + vec2 v = vertex.xy * scale + offset; + gl_Position = vec4(v, 0.0, 1.0); +} + +/* clang-format off */ +[fragment] + +uniform sampler2D source; //texunit:0 +/* clang-format on */ + +uniform vec2 eye_center; +uniform float k1; +uniform float k2; +uniform float upscale; +uniform float aspect_ratio; + +varying vec2 uv_interp; + +void main() { + vec2 coords = uv_interp; + vec2 offset = coords - eye_center; + + // take aspect ratio into account + offset.y /= aspect_ratio; + + // distort + vec2 offset_sq = offset * offset; + float radius_sq = offset_sq.x + offset_sq.y; + float radius_s4 = radius_sq * radius_sq; + float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); + offset *= distortion_scale; + + // reapply aspect ratio + offset.y *= aspect_ratio; + + // add our eye center back in + coords = offset + eye_center; + coords /= upscale; + + // and check our color + if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { + gl_FragColor = vec4(0.0, 0.0, 0.0, 1.0); + } else { + coords = (coords + vec2(1.0)) / vec2(2.0); + gl_FragColor = texture2D(source, coords); + } +} diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl index da4c3a84f1..15b90a7771 100644 --- a/drivers/gles2/shaders/scene.glsl +++ b/drivers/gles2/shaders/scene.glsl @@ -15,6 +15,7 @@ precision highp int; #define M_PI 3.14159265359 + // // attributes // @@ -27,15 +28,15 @@ attribute vec3 normal_attrib; // attrib:1 attribute vec4 tangent_attrib; // attrib:2 #endif -#ifdef ENABLE_COLOR_INTERP +#if defined(ENABLE_COLOR_INTERP) attribute vec4 color_attrib; // attrib:3 #endif -#ifdef ENABLE_UV_INTERP +#if defined(ENABLE_UV_INTERP) attribute vec2 uv_attrib; // attrib:4 #endif -#ifdef ENABLE_UV2_INTERP +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) attribute vec2 uv2_attrib; // attrib:5 #endif @@ -43,9 +44,9 @@ attribute vec2 uv2_attrib; // attrib:5 #ifdef USE_SKELETON_SOFTWARE -attribute highp vec4 bone_transform_row_0; // attrib:8 -attribute highp vec4 bone_transform_row_1; // attrib:9 -attribute highp vec4 bone_transform_row_2; // attrib:10 +attribute highp vec4 bone_transform_row_0; // attrib:13 +attribute highp vec4 bone_transform_row_1; // attrib:14 +attribute highp vec4 bone_transform_row_2; // attrib:15 #else @@ -74,17 +75,15 @@ attribute highp vec4 instance_custom_data; // attrib:12 // uniforms // -uniform mat4 camera_matrix; -uniform mat4 camera_inverse_matrix; -uniform mat4 projection_matrix; -uniform mat4 projection_inverse_matrix; +uniform highp mat4 camera_matrix; +uniform highp mat4 camera_inverse_matrix; +uniform highp mat4 projection_matrix; +uniform highp mat4 projection_inverse_matrix; -uniform mat4 world_transform; +uniform highp mat4 world_transform; uniform highp float time; -uniform float normal_mult; - #ifdef RENDER_DEPTH uniform float light_bias; uniform float light_normal_bias; @@ -102,15 +101,15 @@ varying vec3 tangent_interp; varying vec3 binormal_interp; #endif -#ifdef ENABLE_COLOR_INTERP +#if defined(ENABLE_COLOR_INTERP) varying vec4 color_interp; #endif -#ifdef ENABLE_UV_INTERP +#if defined(ENABLE_UV_INTERP) varying vec2 uv_interp; #endif -#ifdef ENABLE_UV2_INTERP +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) varying vec2 uv2_interp; #endif @@ -130,11 +129,6 @@ uniform highp float shadow_dual_paraboloid_render_side; #if defined(USE_SHADOW) && defined(USE_LIGHTING) -#ifdef LIGHT_MODE_DIRECTIONAL -uniform highp sampler2D light_directional_shadow; // texunit:-3 -uniform highp vec4 light_split_offsets; -#endif - uniform highp mat4 light_shadow_matrix; varying highp vec4 shadow_coord; @@ -160,22 +154,22 @@ varying highp vec3 diffuse_interp; varying highp vec3 specular_interp; // general for all lights -uniform vec4 light_color; -uniform float light_specular; +uniform highp vec4 light_color; +uniform highp float light_specular; // directional -uniform vec3 light_direction; +uniform highp vec3 light_direction; // omni -uniform vec3 light_position; +uniform highp vec3 light_position; -uniform float light_range; -uniform vec4 light_attenuation; +uniform highp float light_range; +uniform highp float light_attenuation; // spot -uniform float light_spot_attenuation; -uniform float light_spot_range; -uniform float light_spot_angle; +uniform highp float light_spot_attenuation; +uniform highp float light_spot_range; +uniform highp float light_spot_angle; void light_compute( vec3 N, @@ -251,7 +245,7 @@ void light_compute( float cLdotH = max(dot(L, H), 0.0); float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; float blinn = pow(cNdotH, shininess); - blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); #endif @@ -262,6 +256,60 @@ void light_compute( #endif +#ifdef USE_VERTEX_LIGHTING + +#ifdef USE_REFLECTION_PROBE1 + +uniform highp mat4 refprobe1_local_matrix; +varying mediump vec4 refprobe1_reflection_normal_blend; +uniform highp vec3 refprobe1_box_extents; + +#ifndef USE_LIGHTMAP +varying mediump vec3 refprobe1_ambient_normal; +#endif + +#endif //reflection probe1 + +#ifdef USE_REFLECTION_PROBE2 + +uniform highp mat4 refprobe2_local_matrix; +varying mediump vec4 refprobe2_reflection_normal_blend; +uniform highp vec3 refprobe2_box_extents; + +#ifndef USE_LIGHTMAP +varying mediump vec3 refprobe2_ambient_normal; +#endif + +#endif //reflection probe2 + +#endif //vertex lighting for refprobes + +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +varying vec4 fog_interp; + +uniform mediump vec4 fog_color_base; +#ifdef LIGHT_MODE_DIRECTIONAL +uniform mediump vec4 fog_sun_color_amount; +#endif + +uniform bool fog_transmit_enabled; +uniform mediump float fog_transmit_curve; + +#ifdef FOG_DEPTH_ENABLED +uniform highp float fog_depth_begin; +uniform mediump float fog_depth_curve; +uniform mediump float fog_max_distance; +#endif + +#ifdef FOG_HEIGHT_ENABLED +uniform highp float fog_height_min; +uniform highp float fog_height_max; +uniform mediump float fog_height_curve; +#endif + +#endif //fog + void main() { highp vec4 vertex = vertex_attrib; @@ -277,29 +325,29 @@ void main() { vec4(0.0, 0.0, 0.0, 1.0)); world_matrix = world_matrix * transpose(m); } + #endif - vec3 normal = normal_attrib * normal_mult; + vec3 normal = normal_attrib; #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) vec3 tangent = tangent_attrib.xyz; - tangent *= normal_mult; float binormalf = tangent_attrib.a; vec3 binormal = normalize(cross(normal, tangent) * binormalf); #endif -#ifdef ENABLE_COLOR_INTERP +#if defined(ENABLE_COLOR_INTERP) color_interp = color_attrib; #ifdef USE_INSTANCING color_interp *= instance_color; #endif #endif -#ifdef ENABLE_UV_INTERP +#if defined(ENABLE_UV_INTERP) uv_interp = uv_attrib; #endif -#ifdef ENABLE_UV2_INTERP +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) uv2_interp = uv2_attrib; #endif @@ -308,7 +356,7 @@ void main() { normal = normalize((world_matrix * vec4(normal, 0.0)).xyz); #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent = normalize((world_matrix * vec4(tangent, 0.0)), xyz); + tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz); binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz); #endif #endif @@ -354,7 +402,7 @@ void main() { #endif - mat4 modelview = camera_matrix * world_matrix; + mat4 modelview = camera_inverse_matrix * world_matrix; float roughness = 1.0; #define world_transform world_matrix @@ -381,11 +429,11 @@ VERTEX_SHADER_CODE #endif #if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED) - vertex = camera_matrix * vertex; - normal = normalize((camera_matrix * vec4(normal, 0.0)).xyz); + vertex = camera_inverse_matrix * vertex; + normal = normalize((camera_inverse_matrix * vec4(normal, 0.0)).xyz); #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) - tangent = normalize((camera_matrix * vec4(tangent, 0.0)).xyz); - binormal = normalize((camera_matrix * vec4(binormal, 0.0)).xyz); + tangent = normalize((camera_inverse_matrix * vec4(tangent, 0.0)).xyz); + binormal = normalize((camera_inverse_matrix * vec4(binormal, 0.0)).xyz); #endif #endif @@ -438,10 +486,15 @@ VERTEX_SHADER_CODE float normalized_distance = light_length / light_range; - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); + if (normalized_distance < 1.0) { + + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - vec3 attenuation = vec3(omni_attenuation); - light_att = vec3(omni_attenuation); + vec3 attenuation = vec3(omni_attenuation); + light_att = vec3(omni_attenuation); + } else { + light_att = vec3(0.0); + } L = normalize(light_vec); @@ -453,17 +506,30 @@ VERTEX_SHADER_CODE float light_length = length(light_rel_vec); float normalized_distance = light_length / light_range; - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); - vec3 spot_dir = light_direction; + if (normalized_distance < 1.0) { + + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); + vec3 spot_dir = light_direction; + + float spot_cutoff = light_spot_angle; - float spot_cutoff = light_spot_angle; + float angle = dot(-normalize(light_rel_vec), spot_dir); - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + if (angle > spot_cutoff) { - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + float scos = max(angle, spot_cutoff); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + + spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + + light_att = vec3(spot_attenuation); + } else { + light_att = vec3(0.0); + } + } else { + light_att = vec3(0.0); + } - light_att = vec3(spot_attenuation); L = normalize(light_rel_vec); #endif @@ -492,12 +558,86 @@ VERTEX_SHADER_CODE #if defined(LIGHT_USE_PSSM4) shadow_coord3 = light_shadow_matrix3 * vi4; - shadow_coord3 = light_shadow_matrix3 * vi4; + shadow_coord4 = light_shadow_matrix4 * vi4; #endif #endif //use shadow and use lighting +#ifdef USE_VERTEX_LIGHTING + +#ifdef USE_REFLECTION_PROBE1 + { + vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); + vec3 local_pos = (refprobe1_local_matrix * vec4(vertex_interp, 1.0)).xyz; + vec3 inner_pos = abs(local_pos / refprobe1_box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + + { + vec3 local_ref_vec = (refprobe1_local_matrix * vec4(ref_normal, 0.0)).xyz; + refprobe1_reflection_normal_blend.xyz = local_ref_vec; + refprobe1_reflection_normal_blend.a = blend; + } +#ifndef USE_LIGHTMAP + + refprobe1_ambient_normal = (refprobe1_local_matrix * vec4(normal_interp, 0.0)).xyz; +#endif + } + +#endif //USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + { + vec3 ref_normal = normalize(reflect(vertex_interp, normal_interp)); + vec3 local_pos = (refprobe2_local_matrix * vec4(vertex_interp, 1.0)).xyz; + vec3 inner_pos = abs(local_pos / refprobe2_box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + + { + vec3 local_ref_vec = (refprobe2_local_matrix * vec4(ref_normal, 0.0)).xyz; + refprobe2_reflection_normal_blend.xyz = local_ref_vec; + refprobe2_reflection_normal_blend.a = blend; + } +#ifndef USE_LIGHTMAP + + refprobe2_ambient_normal = (refprobe2_local_matrix * vec4(normal_interp, 0.0)).xyz; +#endif + } + +#endif //USE_REFLECTION_PROBE2 + +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + + float fog_amount = 0.0; + +#ifdef LIGHT_MODE_DIRECTIONAL + + vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex_interp), light_direction), 0.0), 8.0)); +#else + vec3 fog_color = fog_color_base.rgb; +#endif + +#ifdef FOG_DEPTH_ENABLED + + { + + float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); + + fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; + } +#endif + +#ifdef FOG_HEIGHT_ENABLED + { + float y = (camera_matrix * vec4(vertex_interp, 1.0)).y; + fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); + } +#endif + fog_interp = vec4(fog_color, fog_amount); + +#endif //fog + +#endif //use vertex lighting gl_Position = projection_matrix * vec4(vertex_interp, 1.0); } @@ -527,17 +667,17 @@ precision highp int; // uniforms // -uniform mat4 camera_matrix; +uniform highp mat4 camera_matrix; /* clang-format on */ -uniform mat4 camera_inverse_matrix; -uniform mat4 projection_matrix; -uniform mat4 projection_inverse_matrix; +uniform highp mat4 camera_inverse_matrix; +uniform highp mat4 projection_matrix; +uniform highp mat4 projection_inverse_matrix; -uniform mat4 world_transform; +uniform highp mat4 world_transform; uniform highp float time; -#ifdef SCREEN_UV_USED +#if defined(SCREEN_UV_USED) uniform vec2 screen_pixel_size; #endif @@ -548,10 +688,168 @@ uniform vec2 screen_pixel_size; uniform highp sampler2D screen_texture; //texunit:-4 #endif -#ifdef USE_RADIANCE_MAP +#ifdef USE_REFLECTION_PROBE1 + +#ifdef USE_VERTEX_LIGHTING + +varying mediump vec4 refprobe1_reflection_normal_blend; +#ifndef USE_LIGHTMAP +varying mediump vec3 refprobe1_ambient_normal; +#endif + +#else + +uniform bool refprobe1_use_box_project; +uniform highp vec3 refprobe1_box_extents; +uniform vec3 refprobe1_box_offset; +uniform highp mat4 refprobe1_local_matrix; + +#endif //use vertex lighting + +uniform bool refprobe1_exterior; + +uniform highp samplerCube reflection_probe1; //texunit:-5 + +uniform float refprobe1_intensity; +uniform vec4 refprobe1_ambient; + +#endif //USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + +#ifdef USE_VERTEX_LIGHTING + +varying mediump vec4 refprobe2_reflection_normal_blend; +#ifndef USE_LIGHTMAP +varying mediump vec3 refprobe2_ambient_normal; +#endif + +#else + +uniform bool refprobe2_use_box_project; +uniform highp vec3 refprobe2_box_extents; +uniform vec3 refprobe2_box_offset; +uniform highp mat4 refprobe2_local_matrix; + +#endif //use vertex lighting + +uniform bool refprobe2_exterior; + +uniform highp samplerCube reflection_probe2; //texunit:-6 + +uniform float refprobe2_intensity; +uniform vec4 refprobe2_ambient; + +#endif //USE_REFLECTION_PROBE2 #define RADIANCE_MAX_LOD 6.0 +#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + +void reflection_process(samplerCube reflection_map, +#ifdef USE_VERTEX_LIGHTING + vec3 ref_normal, +#ifndef USE_LIGHTMAP + vec3 amb_normal, +#endif + float ref_blend, + +#else //no vertex lighting + vec3 normal, vec3 vertex, + mat4 local_matrix, + bool use_box_project, vec3 box_extents, vec3 box_offset, +#endif //vertex lighting + bool exterior, float intensity, vec4 ref_ambient, float roughness, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { + + vec4 reflection; + +#ifdef USE_VERTEX_LIGHTING + + reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; + + float blend = ref_blend; //crappier blend formula for vertex + blend *= blend; + blend = max(0.0, 1.0 - blend); + +#else //fragment lighting + + vec3 local_pos = (local_matrix * vec4(vertex, 1.0)).xyz; + + if (any(greaterThan(abs(local_pos), box_extents))) { //out of the reflection box + return; + } + + vec3 inner_pos = abs(local_pos / box_extents); + float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z)); + blend = mix(length(inner_pos), blend, blend); + blend *= blend; + blend = max(0.0, 1.0 - blend); + + //reflect and make local + vec3 ref_normal = normalize(reflect(vertex, normal)); + ref_normal = (local_matrix * vec4(ref_normal, 0.0)).xyz; + + if (use_box_project) { //box project + + vec3 nrdir = normalize(ref_normal); + vec3 rbmax = (box_extents - local_pos) / nrdir; + vec3 rbmin = (-box_extents - local_pos) / nrdir; + + vec3 rbminmax = mix(rbmin, rbmax, vec3(greaterThan(nrdir, vec3(0.0, 0.0, 0.0)))); + + float fa = min(min(rbminmax.x, rbminmax.y), rbminmax.z); + vec3 posonbox = local_pos + nrdir * fa; + ref_normal = posonbox - box_offset.xyz; + } + + reflection.rgb = textureCubeLod(reflection_map, ref_normal, roughness * RADIANCE_MAX_LOD).rgb; +#endif + + if (exterior) { + reflection.rgb = mix(skybox, reflection.rgb, blend); + } + reflection.rgb *= intensity; + reflection.a = blend; + reflection.rgb *= blend; + + reflection_accum += reflection; + +#ifndef USE_LIGHTMAP + + vec4 ambient_out; +#ifndef USE_VERTEX_LIGHTING + + vec3 amb_normal = (local_matrix * vec4(normal, 0.0)).xyz; +#endif + + ambient_out.rgb = textureCubeLod(reflection_map, amb_normal, RADIANCE_MAX_LOD).rgb; + ambient_out.rgb = mix(ref_ambient.rgb, ambient_out.rgb, ref_ambient.a); + if (exterior) { + ambient_out.rgb = mix(ambient, ambient_out.rgb, blend); + } + + ambient_out.a = blend; + ambient_out.rgb *= blend; + ambient_accum += ambient_out; + +#endif +} + +#endif //use refprobe 1 or 2 + +#ifdef USE_LIGHTMAP +uniform mediump sampler2D lightmap; //texunit:-4 +uniform mediump float lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE +uniform mediump vec4[12] lightmap_captures; +uniform bool lightmap_capture_sky; + +#endif + +#ifdef USE_RADIANCE_MAP + uniform samplerCube radiance_map; // texunit:-2 uniform mat4 radiance_inverse_xform; @@ -572,27 +870,29 @@ uniform float ambient_energy; varying highp vec3 diffuse_interp; varying highp vec3 specular_interp; +uniform highp vec3 light_direction; //may be used by fog, so leave here + #else //done in fragment // general for all lights -uniform vec4 light_color; -uniform float light_specular; +uniform highp vec4 light_color; +uniform highp float light_specular; // directional -uniform vec3 light_direction; +uniform highp vec3 light_direction; // omni -uniform vec3 light_position; +uniform highp vec3 light_position; -uniform vec4 light_attenuation; +uniform highp float light_attenuation; // spot -uniform float light_spot_attenuation; -uniform float light_spot_range; -uniform float light_spot_angle; +uniform highp float light_spot_attenuation; +uniform highp float light_spot_range; +uniform highp float light_spot_angle; #endif //this is needed outside above if because dual paraboloid wants it -uniform float light_range; +uniform highp float light_range; #ifdef USE_SHADOW @@ -640,24 +940,25 @@ varying vec3 tangent_interp; varying vec3 binormal_interp; #endif -#ifdef ENABLE_COLOR_INTERP +#if defined(ENABLE_COLOR_INTERP) varying vec4 color_interp; #endif -#ifdef ENABLE_UV_INTERP +#if defined(ENABLE_UV_INTERP) varying vec2 uv_interp; #endif -#ifdef ENABLE_UV2_INTERP +#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP) varying vec2 uv2_interp; #endif varying vec3 view_interp; -vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) { - float dielectric = (0.034 * 2.0) * specular; - // energy conservation - return mix(vec3(dielectric), albedo, metallic); // TODO: reference? +vec3 F0(float metallic, float specular, vec3 albedo) { + float dielectric = 0.16 * specular * specular; + // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; + // see https://google.github.io/filament/Filament.md.html + return mix(vec3(dielectric), albedo, vec3(metallic)); } /* clang-format off */ @@ -690,6 +991,7 @@ varying highp float dp_clip; // E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014). // Eqns 71-72 and 85-86 (see also Eqns 43 and 80). +/* float G_GGX_2cos(float cos_theta_m, float alpha) { // Schlick's approximation // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994) @@ -702,6 +1004,13 @@ float G_GGX_2cos(float cos_theta_m, float alpha) { // float sin2 = (1.0 - cos2); // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2)); } +*/ + +// This approximates G_GGX_2cos(cos_theta_l, alpha) * G_GGX_2cos(cos_theta_v, alpha) +// See Filament docs, Specular G section. +float V_GGX(float cos_theta_l, float cos_theta_v, float alpha) { + return 0.5 / mix(2.0 * cos_theta_l * cos_theta_v, cos_theta_l + cos_theta_v, alpha); +} float D_GGX(float cos_theta_m, float alpha) { float alpha2 = alpha * alpha; @@ -709,6 +1018,7 @@ float D_GGX(float cos_theta_m, float alpha) { return alpha2 / (M_PI * d * d); } +/* float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { float cos2 = cos_theta_m * cos_theta_m; float sin2 = (1.0 - cos2); @@ -716,14 +1026,30 @@ float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, fl float s_y = alpha_y * sin_phi; return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x * s_x + s_y * s_y) * sin2), 0.001); } +*/ -float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) { - float cos2 = cos_theta_m * cos_theta_m; +// This approximates G_GGX_anisotropic_2cos(cos_theta_l, ...) * G_GGX_anisotropic_2cos(cos_theta_v, ...) +// See Filament docs, Anisotropic specular BRDF section. +float V_GGX_anisotropic(float alpha_x, float alpha_y, float TdotV, float TdotL, float BdotV, float BdotL, float NdotV, float NdotL) { + float Lambda_V = NdotL * length(vec3(alpha_x * TdotV, alpha_y * BdotV, NdotV)); + float Lambda_L = NdotV * length(vec3(alpha_x * TdotL, alpha_y * BdotL, NdotL)); + return 0.5 / (Lambda_V + Lambda_L); +} + +float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi, float NdotH) { + float alpha2 = alpha_x * alpha_y; + highp vec3 v = vec3(alpha_y * cos_phi, alpha_x * sin_phi, alpha2 * NdotH); + highp float v2 = dot(v, v); + float w2 = alpha2 / v2; + float D = alpha2 * w2 * w2 * (1.0 / M_PI); + return D; + + /* float cos2 = cos_theta_m * cos_theta_m; float sin2 = (1.0 - cos2); float r_x = cos_phi / alpha_x; float r_y = sin_phi / alpha_y; float d = cos2 + sin2 * (r_x * r_x + r_y * r_y); - return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); + return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001); */ } float SchlickFresnel(float u) { @@ -752,6 +1078,7 @@ void light_compute( float specular_blob_intensity, float roughness, float metallic, + float specular, float rim, float rim_tint, float clearcoat, @@ -792,7 +1119,19 @@ LIGHT_SHADER_CODE float NdotL = dot(N, L); float cNdotL = max(NdotL, 0.0); // clamped NdotL float NdotV = dot(N, V); - float cNdotV = max(NdotV, 0.0); + float cNdotV = max(abs(NdotV), 1e-6); + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + vec3 H = normalize(V + L); +#endif + +#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cNdotH = max(dot(N, H), 0.0); +#endif + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cLdotH = max(dot(L, H), 0.0); +#endif if (metallic < 1.0) { #if defined(DIFFUSE_OREN_NAYAR) @@ -828,13 +1167,9 @@ LIGHT_SHADER_CODE #elif defined(DIFFUSE_BURLEY) { - - vec3 H = normalize(V + L); - float cLdotH = max(0.0, dot(L, H)); - - float FD90 = 0.5 + 2.0 * cLdotH * cLdotH * roughness; - float FdV = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotV); - float FdL = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotL); + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; /* float energyBias = mix(roughness, 0.0, 0.5); @@ -868,20 +1203,18 @@ LIGHT_SHADER_CODE if (roughness > 0.0) { - // D - - float specular_brdf_NL; +#if defined(SPECULAR_SCHLICK_GGX) + vec3 specular_brdf_NL = vec3(0.0); +#else + float specular_brdf_NL = 0.0; +#endif #if defined(SPECULAR_BLINN) //normalized blinn - vec3 H = normalize(V + L); - float cNdotH = max(dot(N, H), 0.0); - float cVdotH = max(dot(V, H), 0.0); - float cLdotH = max(dot(L, H), 0.0); float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; float blinn = pow(cNdotH, shininess); - blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); specular_brdf_NL = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); #elif defined(SPECULAR_PHONG) @@ -890,7 +1223,7 @@ LIGHT_SHADER_CODE float cRdotV = max(0.0, dot(R, V)); float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; float phong = pow(cRdotV, shininess); - phong *= (shininess + 8.0) / (8.0 * 3.141592654); + phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); specular_brdf_NL = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); #elif defined(SPECULAR_TOON) @@ -903,38 +1236,32 @@ LIGHT_SHADER_CODE #elif defined(SPECULAR_DISABLED) // none.. - specular_brdf_NL = 0.0; #elif defined(SPECULAR_SCHLICK_GGX) // shlick+ggx as default - vec3 H = normalize(V + L); - - float cNdotH = max(dot(N, H), 0.0); - float cLdotH = max(dot(L, H), 0.0); - #if defined(LIGHT_USE_ANISOTROPY) - + float alpha = roughness * roughness; float aspect = sqrt(1.0 - anisotropy * 0.9); - float rx = roughness / aspect; - float ry = roughness * aspect; - float ax = rx * rx; - float ay = ry * ry; + float ax = alpha / aspect; + float ay = alpha * aspect; float XdotH = dot(T, H); float YdotH = dot(B, H); - float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); - float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH, cNdotH); + //float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH); + float G = V_GGX_anisotropic(ax, ay, dot(T, V), dot(T, L), dot(B, V), dot(B, L), cNdotV, cNdotL)) #else float alpha = roughness * roughness; float D = D_GGX(cNdotH, alpha); - float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); + //float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); + float G = V_GGX(cNdotL, cNdotV, alpha); #endif // F - //float F0 = 1.0; - //float cLdotH5 = SchlickFresnel(cLdotH); - //float F = mix(cLdotH5, 1.0, F0); + vec3 f0 = F0(metallic, specular, diffuse_color); + float cLdotH5 = SchlickFresnel(cLdotH); + vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); - specular_brdf_NL = cNdotL * D /* F */ * G; + specular_brdf_NL = cNdotL * D * F * G; #endif @@ -942,23 +1269,18 @@ LIGHT_SHADER_CODE specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #if defined(LIGHT_USE_CLEARCOAT) - if (clearcoat_gloss > 0.0) { -#if !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) - vec3 H = normalize(V + L); -#endif + #if !defined(SPECULAR_SCHLICK_GGX) - float cNdotH = max(dot(N, H), 0.0); - float cLdotH = max(dot(L, H), 0.0); - float cLdotH5 = SchlickFresnel(cLdotH); + float cLdotH5 = SchlickFresnel(cLdotH); #endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); - float Fr = mix(.04, 1.0, cLdotH5); - float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + //float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + float Gr = V_GGX(cNdotL, cNdotV, 0.25); - float specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; - } + specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #endif } @@ -971,14 +1293,16 @@ LIGHT_SHADER_CODE #ifdef USE_SHADOW #define SAMPLE_SHADOW_TEXEL(p_shadow, p_pos, p_depth) step(p_depth, texture2D(p_shadow, p_pos).r) +#define SAMPLE_SHADOW_TEXEL_PROJ(p_shadow, p_pos) step(p_pos.z, texture2DProj(p_shadow, p_pos).r) -float sample_shadow( - highp sampler2D shadow, - highp vec2 pos, - highp float depth) { +float sample_shadow(highp sampler2D shadow, highp vec4 spos) { #ifdef SHADOW_MODE_PCF_13 + spos.xyz /= spos.w; + vec2 pos = spos.xy; + float depth = spos.z; + float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); @@ -997,6 +1321,10 @@ float sample_shadow( #ifdef SHADOW_MODE_PCF_5 + spos.xyz /= spos.w; + vec2 pos = spos.xy; + float depth = spos.z; + float avg = SAMPLE_SHADOW_TEXEL(shadow, pos, depth); avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(shadow_pixel_size.x, 0.0), depth); avg += SAMPLE_SHADOW_TEXEL(shadow, pos + vec2(-shadow_pixel_size.x, 0.0), depth); @@ -1008,12 +1336,42 @@ float sample_shadow( #if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) - return SAMPLE_SHADOW_TEXEL(shadow, pos, depth); + return SAMPLE_SHADOW_TEXEL_PROJ(shadow, spos); #endif } #endif +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#if defined(USE_VERTEX_LIGHTING) + +varying vec4 fog_interp; + +#else +uniform mediump vec4 fog_color_base; +#ifdef LIGHT_MODE_DIRECTIONAL +uniform mediump vec4 fog_sun_color_amount; +#endif + +uniform bool fog_transmit_enabled; +uniform mediump float fog_transmit_curve; + +#ifdef FOG_DEPTH_ENABLED +uniform highp float fog_depth_begin; +uniform mediump float fog_depth_curve; +uniform mediump float fog_max_distance; +#endif + +#ifdef FOG_HEIGHT_ENABLED +uniform highp float fog_height_min; +uniform highp float fog_height_max; +uniform mediump float fog_height_curve; +#endif + +#endif //vertex lit +#endif //fog + void main() { #ifdef RENDER_DEPTH_DUAL_PARABOLOID @@ -1034,10 +1392,16 @@ void main() { float clearcoat_gloss = 0.0; float anisotropy = 0.0; vec2 anisotropy_flow = vec2(1.0, 0.0); + float sss_strength = 0.0; //unused float alpha = 1.0; float side = 1.0; + float specular_blob_intensity = 1.0; +#if defined(SPECULAR_TOON) + specular_blob_intensity *= specular * 2.0; +#endif + #if defined(ENABLE_AO) float ao = 1.0; float ao_light_affect = 0.0; @@ -1057,11 +1421,11 @@ void main() { #endif float normaldepth = 1.0; -#ifdef ALPHA_SCISSOR_USED +#if defined(ALPHA_SCISSOR_USED) float alpha_scissor = 0.5; #endif -#ifdef SCREEN_UV_USED +#if defined(SCREEN_UV_USED) vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size; #endif @@ -1077,8 +1441,8 @@ FRAGMENT_SHADER_CODE normalmap.xy = normalmap.xy * 2.0 - 1.0; normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); - // normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; - normal = normalmap; + normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; + //normal = normalmap; #endif normal = normalize(normal); @@ -1091,7 +1455,7 @@ FRAGMENT_SHADER_CODE vec3 eye_position = -normalize(vertex_interp); -#ifdef ALPHA_SCISSOR_USED +#if defined(ALPHA_SCISSOR_USED) if (alpha < alpha_scissor) { discard; } @@ -1123,6 +1487,99 @@ FRAGMENT_SHADER_CODE ambient_light *= ambient_energy; +#if defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + + vec4 ambient_accum = vec4(0.0); + vec4 reflection_accum = vec4(0.0); + +#ifdef USE_REFLECTION_PROBE1 + + reflection_process(reflection_probe1, +#ifdef USE_VERTEX_LIGHTING + refprobe1_reflection_normal_blend.rgb, +#ifndef USE_LIGHTMAP + refprobe1_ambient_normal, +#endif + refprobe1_reflection_normal_blend.a, +#else + normal_interp, vertex_interp, refprobe1_local_matrix, + refprobe1_use_box_project, refprobe1_box_extents, refprobe1_box_offset, +#endif + refprobe1_exterior, refprobe1_intensity, refprobe1_ambient, roughness, + ambient_light, specular_light, reflection_accum, ambient_accum); + +#endif // USE_REFLECTION_PROBE1 + +#ifdef USE_REFLECTION_PROBE2 + + reflection_process(reflection_probe2, +#ifdef USE_VERTEX_LIGHTING + refprobe2_reflection_normal_blend.rgb, +#ifndef USE_LIGHTMAP + refprobe2_ambient_normal, +#endif + refprobe2_reflection_normal_blend.a, +#else + normal_interp, vertex_interp, refprobe2_local_matrix, + refprobe2_use_box_project, refprobe2_box_extents, refprobe2_box_offset, +#endif + refprobe2_exterior, refprobe2_intensity, refprobe2_ambient, roughness, + ambient_light, specular_light, reflection_accum, ambient_accum); + +#endif // USE_REFLECTION_PROBE2 + + if (reflection_accum.a > 0.0) { + specular_light = reflection_accum.rgb / reflection_accum.a; + } + +#ifndef USE_LIGHTMAP + if (ambient_accum.a > 0.0) { + ambient_light = ambient_accum.rgb / ambient_accum.a; + } +#endif + +#endif // defined(USE_REFLECTION_PROBE1) || defined(USE_REFLECTION_PROBE2) + +#ifdef USE_LIGHTMAP + //ambient light will come entirely from lightmap is lightmap is used + ambient_light = texture2D(lightmap, uv2_interp).rgb * lightmap_energy; +#endif + +#ifdef USE_LIGHTMAP_CAPTURE + { + vec3 cone_dirs[12] = vec3[]( + vec3(0, 0, 1), + vec3(0.866025, 0, 0.5), + vec3(0.267617, 0.823639, 0.5), + vec3(-0.700629, 0.509037, 0.5), + vec3(-0.700629, -0.509037, 0.5), + vec3(0.267617, -0.823639, 0.5), + vec3(0, 0, -1), + vec3(0.866025, 0, -0.5), + vec3(0.267617, 0.823639, -0.5), + vec3(-0.700629, 0.509037, -0.5), + vec3(-0.700629, -0.509037, -0.5), + vec3(0.267617, -0.823639, -0.5)); + + vec3 local_normal = normalize(camera_matrix * vec4(normal, 0.0)).xyz; + vec4 captured = vec4(0.0); + float sum = 0.0; + for (int i = 0; i < 12; i++) { + float amount = max(0.0, dot(local_normal, cone_dirs[i])); //not correct, but creates a nice wrap around effect + captured += lightmap_captures[i] * amount; + sum += amount; + } + + captured /= sum; + + if (lightmap_capture_sky) { + ambient_light = mix(ambient_light, captured.rgb, captured.a); + } else { + ambient_light = captured.rgb; + } + } +#endif + #endif //BASE PASS // @@ -1142,20 +1599,24 @@ FRAGMENT_SHADER_CODE float light_length = length(light_vec); float normalized_distance = light_length / light_range; + if (normalized_distance < 1.0) { - float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); + float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation); - light_att = vec3(omni_attenuation); + light_att = vec3(omni_attenuation); + } else { + light_att = vec3(0.0); + } L = normalize(light_vec); #endif #ifdef USE_SHADOW { - highp vec3 splane = shadow_coord.xyz; - float shadow_len = length(splane); + highp vec4 splane = shadow_coord; + float shadow_len = length(splane.xyz); - splane = normalize(splane); + splane.xyz = normalize(splane.xyz); vec4 clamp_rect = light_clamp; @@ -1172,8 +1633,9 @@ FRAGMENT_SHADER_CODE splane.z = shadow_len / light_range; splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw; + splane.w = 1.0; - float shadow = sample_shadow(light_shadow_atlas, splane.xy, splane.z); + float shadow = sample_shadow(light_shadow_atlas, splane); light_att *= shadow; } @@ -1190,6 +1652,121 @@ FRAGMENT_SHADER_CODE float depth_z = -vertex.z; #ifdef USE_SHADOW + +#ifdef USE_VERTEX_LIGHTING + //compute shadows in a mobile friendly way + +#ifdef LIGHT_USE_PSSM4 + //take advantage of prefetch + float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); + float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); + float shadow3 = sample_shadow(light_directional_shadow, shadow_coord3); + float shadow4 = sample_shadow(light_directional_shadow, shadow_coord4); + + if (depth_z < light_split_offsets.w) { + float pssm_fade = 0.0; + float shadow_att = 1.0; +#ifdef LIGHT_USE_PSSM_BLEND + float shadow_att2 = 1.0; + float pssm_blend = 0.0; + bool use_blend = true; +#endif + if (depth_z < light_split_offsets.y) { + if (depth_z < light_split_offsets.x) { + shadow_att = shadow1; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow2; + + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); +#endif + } else { + shadow_att = shadow2; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow3; + + pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#endif + } + } else { + if (depth_z < light_split_offsets.z) { + + shadow_att = shadow3; + +#if defined(LIGHT_USE_PSSM_BLEND) + shadow_att2 = shadow4; + pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); +#endif + + } else { + + shadow_att = shadow4; + pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); + +#if defined(LIGHT_USE_PSSM_BLEND) + use_blend = false; +#endif + } + } +#if defined(LIGHT_USE_PSSM_BLEND) + if (use_blend) { + shadow_att = mix(shadow_att, shadow_att2, pssm_blend); + } +#endif + light_att *= shadow_att; + } + +#endif //LIGHT_USE_PSSM4 + +#ifdef LIGHT_USE_PSSM2 + + //take advantage of prefetch + float shadow1 = sample_shadow(light_directional_shadow, shadow_coord); + float shadow2 = sample_shadow(light_directional_shadow, shadow_coord2); + + if (depth_z < light_split_offsets.y) { + float shadow_att = 1.0; + float pssm_fade = 0.0; + +#ifdef LIGHT_USE_PSSM_BLEND + float shadow_att2 = 1.0; + float pssm_blend = 0.0; + bool use_blend = true; +#endif + if (depth_z < light_split_offsets.x) { + float pssm_fade = 0.0; + shadow_att = shadow1; + +#ifdef LIGHT_USE_PSSM_BLEND + shadow_att2 = shadow2; + pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); +#endif + } else { + + shadow_att = shadow2; + pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); +#ifdef LIGHT_USE_PSSM_BLEND + use_blend = false; +#endif + } +#ifdef LIGHT_USE_PSSM_BLEND + if (use_blend) { + shadow_att = mix(shadow_att, shadow_att2, pssm_blend); + } +#endif + light_att *= shadow_att; + } + +#endif //LIGHT_USE_PSSM2 + +#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) + + light_att *= sample_shadow(light_directional_shadow, shadow_coord); +#endif //orthogonal + +#else //fragment version of pssm + { #ifdef LIGHT_USE_PSSM4 if (depth_z < light_split_offsets.w) { @@ -1199,34 +1776,31 @@ FRAGMENT_SHADER_CODE if (depth_z < light_split_offsets.x) { #endif //pssm2 - vec3 pssm_coord; + highp vec4 pssm_coord; float pssm_fade = 0.0; #ifdef LIGHT_USE_PSSM_BLEND float pssm_blend; - vec3 pssm_coord2; + highp vec4 pssm_coord2; bool use_blend = true; #endif #ifdef LIGHT_USE_PSSM4 + if (depth_z < light_split_offsets.y) { if (depth_z < light_split_offsets.x) { - highp vec4 splane = shadow_coord; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord; #ifdef LIGHT_USE_PSSM_BLEND - splane = shadow_coord2; - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord2; pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif } else { - highp vec4 splane = shadow_coord2; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord2; #ifdef LIGHT_USE_PSSM_BLEND - splane = shadow_coord3; - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord3; pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); #endif @@ -1234,19 +1808,16 @@ FRAGMENT_SHADER_CODE } else { if (depth_z < light_split_offsets.z) { - highp vec4 splane = shadow_coord3; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord3; #if defined(LIGHT_USE_PSSM_BLEND) - splane = shadow_coord4; - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord4; pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z); #endif } else { - highp vec4 splane = shadow_coord4; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord4; pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z); #if defined(LIGHT_USE_PSSM_BLEND) @@ -1260,17 +1831,15 @@ FRAGMENT_SHADER_CODE #ifdef LIGHT_USE_PSSM2 if (depth_z < light_split_offsets.x) { - highp vec4 splane = shadow_coord; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord; #ifdef LIGHT_USE_PSSM_BLEND - splane = shadow_coord2; - pssm_coord2 = splane.xyz / splane.w; + pssm_coord2 = shadow_coord2; pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z); #endif } else { - highp vec4 splane = shadow_coord2; - pssm_coord = splane.xyz / splane.w; + + pssm_coord = shadow_coord2; pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z); #ifdef LIGHT_USE_PSSM_BLEND use_blend = false; @@ -1281,22 +1850,23 @@ FRAGMENT_SHADER_CODE #if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2) { - highp vec4 splane = shadow_coord; - pssm_coord = splane.xyz / splane.w; + pssm_coord = shadow_coord; } #endif - float shadow = sample_shadow(light_directional_shadow, pssm_coord.xy, pssm_coord.z); + float shadow = sample_shadow(light_directional_shadow, pssm_coord); #ifdef LIGHT_USE_PSSM_BLEND if (use_blend) { - shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2.xy, pssm_coord2.z), pssm_blend); + shadow = mix(shadow, sample_shadow(light_directional_shadow, pssm_coord2), pssm_blend); } #endif light_att *= shadow; } } +#endif //use vertex lighting + #endif //use shadow #endif @@ -1311,17 +1881,25 @@ FRAGMENT_SHADER_CODE float light_length = length(light_rel_vec); float normalized_distance = light_length / light_range; - float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation.w); - vec3 spot_dir = light_direction; - - float spot_cutoff = light_spot_angle; + if (normalized_distance < 1.0) { + float spot_attenuation = pow(1.0 - normalized_distance, light_attenuation); + vec3 spot_dir = light_direction; - float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff); - float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + float spot_cutoff = light_spot_angle; + float angle = dot(-normalize(light_rel_vec), spot_dir); - spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); + if (angle > spot_cutoff) { + float scos = max(angle, spot_cutoff); + float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff)); + spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation); - light_att = vec3(spot_attenuation); + light_att = vec3(spot_attenuation); + } else { + light_att = vec3(0.0); + } + } else { + light_att = vec3(0.0); + } L = normalize(light_rel_vec); @@ -1332,17 +1910,17 @@ FRAGMENT_SHADER_CODE highp vec4 splane = shadow_coord; splane.xyz /= splane.w; - float shadow = sample_shadow(light_shadow_atlas, splane.xy, splane.z); + float shadow = sample_shadow(light_shadow_atlas, splane); light_att *= shadow; } #endif -#endif +#endif // LIGHT_MODE_SPOT #ifdef USE_VERTEX_LIGHTING //vertex lighting - specular_light += specular_interp * specular * light_att; + specular_light += specular_interp * specular_blob_intensity * light_att; diffuse_light += diffuse_interp * albedo * light_att; #else @@ -1357,9 +1935,10 @@ FRAGMENT_SHADER_CODE light_att, albedo, transmission, - specular * light_specular, + specular_blob_intensity * light_specular, roughness, metallic, + specular, rim, rim_tint, clearcoat, @@ -1394,23 +1973,79 @@ FRAGMENT_SHADER_CODE // environment BRDF approximation - // TODO shadeless { + +#if defined(DIFFUSE_TOON) + //simplify for toon, as + specular_light *= specular * metallic * albedo * 2.0; +#else + //TODO: this curve is not really designed for gammaspace, should be adjusted const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022); const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04); vec4 r = roughness * c0 + c1; float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0); float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; - vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo); - specular_light *= AB.x * specular_color + AB.y; + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; +#endif } gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha); + + //add emission if in base pass +#ifdef BASE_PASS + gl_FragColor.rgb += emission; +#endif // gl_FragColor = vec4(normal, 1.0); #endif //unshaded +//apply fog +#if defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + +#if defined(USE_VERTEX_LIGHTING) + + gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_interp.rgb, fog_interp.a); +#else //pixel based fog + float fog_amount = 0.0; + +#ifdef LIGHT_MODE_DIRECTIONAL + + vec3 fog_color = mix(fog_color_base.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(eye_position, light_direction), 0.0), 8.0)); +#else + vec3 fog_color = fog_color_base.rgb; +#endif + +#ifdef FOG_DEPTH_ENABLED + + { + + float fog_z = smoothstep(fog_depth_begin, fog_max_distance, length(vertex)); + + fog_amount = pow(fog_z, fog_depth_curve) * fog_color_base.a; + + if (fog_transmit_enabled) { + vec3 total_light = gl_FragColor.rgb; + float transmit = pow(fog_z, fog_transmit_curve); + fog_color = mix(max(total_light, fog_color), fog_color, transmit); + } + } +#endif + +#ifdef FOG_HEIGHT_ENABLED + { + float y = (camera_matrix * vec4(vertex, 1.0)).y; + fog_amount = max(fog_amount, pow(smoothstep(fog_height_min, fog_height_max, y), fog_height_curve)); + } +#endif + + gl_FragColor.rgb = mix(gl_FragColor.rgb, fog_color, fog_amount); + +#endif //use vertex lit + +#endif // defined(FOG_DEPTH_ENABLED) || defined(FOG_HEIGHT_ENABLED) + #endif // not RENDER_DEPTH } diff --git a/drivers/gles2/shaders/stdlib.glsl b/drivers/gles2/shaders/stdlib.glsl index 6bc81a22d8..3674d70c9f 100644 --- a/drivers/gles2/shaders/stdlib.glsl +++ b/drivers/gles2/shaders/stdlib.glsl @@ -35,3 +35,13 @@ highp vec4 texel2DFetch(highp sampler2D tex, ivec2 size, ivec2 coord) { return texture2DLod(tex, vec2(x_coord, y_coord), 0.0); } + +#ifndef USE_GLES_OVER_GL +highp mat4 transpose(highp mat4 src) { + return mat4( + vec4(src[0].x, src[1].x, src[2].x, src[3].x), + vec4(src[0].y, src[1].y, src[2].y, src[3].y), + vec4(src[0].z, src[1].z, src[2].z, src[3].z), + vec4(src[0].w, src[1].w, src[2].w, src[3].w)); +} +#endif diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp index c9bdc6f5c3..4166cb8361 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.cpp +++ b/drivers/gles3/rasterizer_canvas_gles3.cpp @@ -213,12 +213,12 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasGLES3::_bind_canvas_texture(con } else { + texture = texture->get_ptr(); + if (texture->redraw_if_visible) { //check before proxy, because this is usually used with proxies VisualServerRaster::redraw_request(); } - texture = texture->get_ptr(); - if (texture->render_target) texture->render_target->used_in_frame = true; @@ -254,11 +254,12 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasGLES3::_bind_canvas_texture(con } else { + normal_map = normal_map->get_ptr(); + if (normal_map->redraw_if_visible) { //check before proxy, because this is usually used with proxies VisualServerRaster::redraw_request(); } - normal_map = normal_map->get_ptr(); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, normal_map->tex_id); state.current_normal = p_normal_map; @@ -976,7 +977,7 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(particles_cmd->texture, particles_cmd->normal_map); if (texture) { - Size2 texpixel_size(1.0 / (texture->width / particles_cmd->h_frames), 1.0 / (texture->height / particles_cmd->v_frames)); + Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height); state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size); } else { state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, Vector2(1.0, 1.0)); @@ -993,9 +994,6 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur state.canvas_shader.set_uniform(CanvasShaderGLES3::MODELVIEW_MATRIX, state.final_transform * inv_xf); } - state.canvas_shader.set_uniform(CanvasShaderGLES3::H_FRAMES, particles_cmd->h_frames); - state.canvas_shader.set_uniform(CanvasShaderGLES3::V_FRAMES, particles_cmd->v_frames); - glBindVertexArray(data.particle_quad_array); //use particle quad array glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); //bind particle buffer @@ -1072,8 +1070,8 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur glBindVertexArray(0); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); state.using_texture_rect = true; _set_texture_rect_mode(false); @@ -1223,10 +1221,6 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons bool rebind_shader = true; - Size2 rt_size = Size2(storage->frame.current_rt->width, storage->frame.current_rt->height); - - state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); - glBindBuffer(GL_UNIFORM_BUFFER, state.canvas_item_ubo); glBufferData(GL_UNIFORM_BUFFER, sizeof(CanvasItemUBO), &state.canvas_item_ubo_data, GL_DYNAMIC_DRAW); glBindBuffer(GL_UNIFORM_BUFFER, 0); @@ -1344,7 +1338,7 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons last_blend_mode = last_blend_mode != RasterizerStorageGLES3::Shader::CanvasItem::BLEND_MODE_DISABLED ? last_blend_mode : -1; } - if (shader_ptr != shader_cache) { + if (shader_ptr != shader_cache || rebind_shader) { if (shader_ptr->canvas_item.uses_time) { VisualServerRaster::redraw_request(); @@ -1390,12 +1384,12 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons continue; } + t = t->get_ptr(); + if (t->redraw_if_visible) { //check before proxy, because this is usually used with proxies VisualServerRaster::redraw_request(); } - t = t->get_ptr(); - if (storage->config.srgb_decode_supported && t->using_srgb) { //no srgb in 2D glTexParameteri(t->target, _TEXTURE_SRGB_DECODE_EXT, _SKIP_DECODE_EXT); @@ -1661,6 +1655,14 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons if (current_clip) { glDisable(GL_SCISSOR_TEST); } + //disable states that may have been used + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_DISTANCE_FIELD, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SKELETON, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_PARTICLES, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_LIGHTING, false); + state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_SHADOWS, false); } void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_shadow) { @@ -1871,6 +1873,39 @@ void RasterizerCanvasGLES3::draw_generic_textured_rect(const Rect2 &p_rect, cons glDrawArrays(GL_TRIANGLE_FAN, 0, 4); } +void RasterizerCanvasGLES3::draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + Vector2 half_size; + if (storage->frame.current_rt) { + half_size = Vector2(storage->frame.current_rt->width, storage->frame.current_rt->height); + } else { + half_size = OS::get_singleton()->get_window_size(); + } + half_size *= 0.5; + Vector2 offset((p_rect.position.x - half_size.x) / half_size.x, (p_rect.position.y - half_size.y) / half_size.y); + Vector2 scale(p_rect.size.x / half_size.x, p_rect.size.y / half_size.y); + + float aspect_ratio = p_rect.size.x / p_rect.size.y; + + // setup our lens shader + state.lens_shader.bind(); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::OFFSET, offset); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::SCALE, scale); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::K1, p_k1); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::K2, p_k2); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::EYE_CENTER, p_eye_center); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::UPSCALE, p_oversample); + state.lens_shader.set_uniform(LensDistortedShaderGLES3::ASPECT_RATIO, aspect_ratio); + + glBindBufferBase(GL_UNIFORM_BUFFER, 0, state.canvas_item_ubo); + glBindVertexArray(data.canvas_quad_array); + + // and draw + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + + glBindVertexArray(0); + glBindBufferBase(GL_UNIFORM_BUFFER, 0, 0); +} + void RasterizerCanvasGLES3::draw_window_margins(int *black_margin, RID *black_image) { Vector2 window_size = OS::get_singleton()->get_window_size(); @@ -1996,6 +2031,7 @@ void RasterizerCanvasGLES3::initialize() { { uint32_t poly_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); poly_size *= 1024; //kb poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float)); glGenBuffers(1, &data.polygon_buffer); @@ -2043,6 +2079,7 @@ void RasterizerCanvasGLES3::initialize() { glGenVertexArrays(1, &data.polygon_buffer_pointer_array); uint32_t index_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", PROPERTY_HINT_RANGE, "0,256,1,or_greater")); index_size *= 1024; //kb glGenBuffers(1, &data.polygon_index_buffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer); @@ -2060,6 +2097,7 @@ void RasterizerCanvasGLES3::initialize() { state.canvas_shader.init(); state.canvas_shader.set_base_material_tex_index(2); state.canvas_shadow_shader.init(); + state.lens_shader.init(); state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); state.canvas_shadow_shader.set_conditional(CanvasShadowShaderGLES3::USE_RGBA_SHADOWS, storage->config.use_rgba_2d_shadows); diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h index bc4ea80328..3f306003b4 100644 --- a/drivers/gles3/rasterizer_canvas_gles3.h +++ b/drivers/gles3/rasterizer_canvas_gles3.h @@ -35,6 +35,7 @@ #include "servers/visual/rasterizer.h" #include "shaders/canvas_shadow.glsl.gen.h" +#include "shaders/lens_distorted.glsl.gen.h" class RasterizerSceneGLES3; @@ -72,6 +73,7 @@ public: bool canvas_texscreen_used; CanvasShaderGLES3 canvas_shader; CanvasShadowShaderGLES3 canvas_shadow_shader; + LensDistortedShaderGLES3 lens_shader; bool using_texture_rect; bool using_ninepatch; @@ -141,6 +143,7 @@ public: virtual void reset_canvas(); void draw_generic_textured_rect(const Rect2 &p_rect, const Rect2 &p_src); + void draw_lens_distortion_rect(const Rect2 &p_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); void initialize(); void finalize(); diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp index d3f6dcd497..8242d214d3 100644 --- a/drivers/gles3/rasterizer_gles3.cpp +++ b/drivers/gles3/rasterizer_gles3.cpp @@ -32,7 +32,7 @@ #include "core/os/os.h" #include "core/project_settings.h" -#include "gl_context/context_gl.h" +#include "drivers/gl_context/context_gl.h" RasterizerStorage *RasterizerGLES3::get_storage() { @@ -73,12 +73,12 @@ RasterizerScene *RasterizerGLES3::get_scene() { #define _EXT_DEBUG_SEVERITY_LOW_ARB 0x9148 #define _EXT_DEBUG_OUTPUT 0x92E0 -#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED) -#define GLAPIENTRY APIENTRY -#else -#define GLAPIENTRY +#if defined(MINGW_ENABLED) || defined(_MSC_VER) +#define strcpy strcpy_s #endif +#ifdef GLAD_ENABLED +// Restricting to GLAD as only used in initialize() with GLAD_GL_ARB_debug_output static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) { if (type == _EXT_DEBUG_TYPE_OTHER_ARB) @@ -123,6 +123,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL ERR_PRINTS(output); } +#endif // GLAD_ENABLED typedef void (*DEBUGPROCARB)(GLenum source, GLenum type, @@ -359,6 +360,26 @@ void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Re #endif } +void RasterizerGLES3::output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample) { + ERR_FAIL_COND(storage->frame.current_rt); + + RasterizerStorageGLES3::RenderTarget *rt = storage->render_target_owner.getornull(p_render_target); + ERR_FAIL_COND(!rt); + + glDisable(GL_BLEND); + + // render to our framebuffer + glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo); + + // output our texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, rt->color); + + canvas->draw_lens_distortion_rect(p_screen_rect, p_k1, p_k2, p_eye_center, p_oversample); + + glBindTexture(GL_TEXTURE_2D, 0); +} + void RasterizerGLES3::end_frame(bool p_swap_buffers) { if (OS::get_singleton()->is_layered_allowed()) { @@ -405,10 +426,10 @@ void RasterizerGLES3::make_current() { void RasterizerGLES3::register_config() { - GLOBAL_DEF("rendering/quality/filters/use_nearest_mipmap_filter", false); GLOBAL_DEF("rendering/quality/filters/anisotropic_filter_level", 4); ProjectSettings::get_singleton()->set_custom_property_info("rendering/quality/filters/anisotropic_filter_level", PropertyInfo(Variant::INT, "rendering/quality/filters/anisotropic_filter_level", PROPERTY_HINT_RANGE, "1,16,1")); GLOBAL_DEF("rendering/limits/time/time_rollover_secs", 3600); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/time/time_rollover_secs", PropertyInfo(Variant::REAL, "rendering/limits/time/time_rollover_secs", PROPERTY_HINT_RANGE, "0,10000,1,or_greater")); } RasterizerGLES3::RasterizerGLES3() { diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h index 0a264caf8f..477e0dfd48 100644 --- a/drivers/gles3/rasterizer_gles3.h +++ b/drivers/gles3/rasterizer_gles3.h @@ -59,6 +59,7 @@ public: virtual void restore_render_target(); virtual void clear_render_target(const Color &p_color); virtual void blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen = 0); + virtual void output_lens_distorted_to_screen(RID p_render_target, const Rect2 &p_screen_rect, float p_k1, float p_k2, const Vector2 &p_eye_center, float p_oversample); virtual void end_frame(bool p_swap_buffers); virtual void finalize(); @@ -66,6 +67,8 @@ public: static void make_current(); static void register_config(); + virtual bool is_low_end() const { return false; } + RasterizerGLES3(); ~RasterizerGLES3(); }; diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp index 086829f9ba..ffe9e1c831 100644 --- a/drivers/gles3/rasterizer_scene_gles3.cpp +++ b/drivers/gles3/rasterizer_scene_gles3.cpp @@ -51,26 +51,6 @@ static const GLenum _cube_side_enum[6] = { }; -static _FORCE_INLINE_ void store_transform2d(const Transform2D &p_mtx, float *p_array) { - - p_array[0] = p_mtx.elements[0][0]; - p_array[1] = p_mtx.elements[0][1]; - p_array[2] = 0; - p_array[3] = 0; - p_array[4] = p_mtx.elements[1][0]; - p_array[5] = p_mtx.elements[1][1]; - p_array[6] = 0; - p_array[7] = 0; - p_array[8] = 0; - p_array[9] = 0; - p_array[10] = 1; - p_array[11] = 0; - p_array[12] = p_mtx.elements[2][0]; - p_array[13] = p_mtx.elements[2][1]; - p_array[14] = 0; - p_array[15] = 1; -} - static _FORCE_INLINE_ void store_transform(const Transform &p_mtx, float *p_array) { p_array[0] = p_mtx.basis.elements[0][0]; p_array[1] = p_mtx.basis.elements[1][0]; @@ -673,7 +653,7 @@ bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance int best_free = -1; int best_used = -1; - uint64_t best_used_frame; + uint64_t best_used_frame = 0; for (int i = 0; i < reflection_atlas->reflections.size(); i++) { if (reflection_atlas->reflections[i].owner == RID()) { @@ -866,7 +846,7 @@ void RasterizerSceneGLES3::environment_set_dof_blur_near(RID p_env, bool p_enabl env->dof_blur_near_amount = p_amount; env->dof_blur_near_quality = p_quality; } -void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale) { +void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); @@ -879,6 +859,7 @@ void RasterizerSceneGLES3::environment_set_glow(RID p_env, bool p_enable, int p_ env->glow_blend_mode = p_blend_mode; env->glow_hdr_bleed_threshold = p_hdr_bleed_threshold; env->glow_hdr_bleed_scale = p_hdr_bleed_scale; + env->glow_hdr_luminance_cap = p_hdr_luminance_cap; env->glow_bicubic_upscale = p_bicubic_upscale; } void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) { @@ -954,13 +935,14 @@ void RasterizerSceneGLES3::environment_set_fog(RID p_env, bool p_enable, const C env->fog_sun_amount = p_sun_amount; } -void RasterizerSceneGLES3::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) { +void RasterizerSceneGLES3::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve) { Environment *env = environment_owner.getornull(p_env); ERR_FAIL_COND(!env); env->fog_depth_enabled = p_enable; env->fog_depth_begin = p_depth_begin; + env->fog_depth_end = p_depth_end; env->fog_depth_curve = p_depth_curve; env->fog_transmit_enabled = p_transmit; env->fog_transmit_curve = p_transmit_curve; @@ -1202,18 +1184,19 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m glActiveTexture(GL_TEXTURE0 + i); - GLenum target; + GLenum target = GL_TEXTURE_2D; GLuint tex = 0; RasterizerStorageGLES3::Texture *t = storage->texture_owner.getptr(textures[i]); if (t) { + t = t->get_ptr(); //resolve for proxies + if (t->redraw_if_visible) { //must check before proxy because this is often used with proxies VisualServerRaster::redraw_request(); } - t = t->get_ptr(); //resolve for proxies #ifdef TOOLS_ENABLED if (t->detect_3d) { t->detect_3d(t->detect_3d_ud); @@ -1266,14 +1249,11 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m case ShaderLanguage::TYPE_SAMPLER3D: { target = GL_TEXTURE_3D; + tex = storage->resources.white_tex_3d; - switch (texture_hints[i]) { - - // TODO - default: { - tex = storage->resources.white_tex_3d; - } break; - } + //switch (texture_hints[i]) { + // TODO + //} } break; @@ -1282,6 +1262,8 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m case ShaderLanguage::TYPE_SAMPLER2DARRAY: { // TODO } break; + + default: {} } } @@ -1449,7 +1431,16 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo if (particles->draw_order == VS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->particle_valid_histories[1]) { glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffer_histories[1]); //modify the buffer, this was used 2 frames ago so it should be good enough for flushing - RasterizerGLES3Particle *particle_array = (RasterizerGLES3Particle *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 24 * sizeof(float), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT); + RasterizerGLES3Particle *particle_array; +#ifndef __EMSCRIPTEN__ + particle_array = static_cast<RasterizerGLES3Particle *>(glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 24 * sizeof(float), GL_MAP_READ_BIT | GL_MAP_WRITE_BIT)); +#else + PoolVector<RasterizerGLES3Particle> particle_vector; + particle_vector.resize(particles->amount); + PoolVector<RasterizerGLES3Particle>::Write w = particle_vector.write(); + particle_array = w.ptr(); + glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), particle_array); +#endif SortArray<RasterizerGLES3Particle, RasterizerGLES3ParticleSort> sorter; @@ -1461,7 +1452,17 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo sorter.sort(particle_array, particles->amount); +#ifndef __EMSCRIPTEN__ glUnmapBuffer(GL_ARRAY_BUFFER); +#else + w = PoolVector<RasterizerGLES3Particle>::Write(); + particle_array = NULL; + { + PoolVector<RasterizerGLES3Particle>::Read r = particle_vector.read(); + glBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * sizeof(RasterizerGLES3Particle), r.ptr()); + } + particle_vector = PoolVector<RasterizerGLES3Particle>(); +#endif #ifdef DEBUG_ENABLED if (state.debug_draw == VS::VIEWPORT_DEBUG_DRAW_WIREFRAME && s->instancing_array_wireframe_id) { glBindVertexArray(s->instancing_array_wireframe_id); // use the wireframe instancing array ID @@ -1509,6 +1510,7 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo } } break; + default: {} } } @@ -1830,6 +1832,7 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) { } } break; + default: {} } } @@ -2221,7 +2224,6 @@ void RasterizerSceneGLES3::_render_list(RenderList::Element **p_elements, int p_ _set_cull(e->sort_key & RenderList::SORT_KEY_MIRROR_FLAG, e->sort_key & RenderList::SORT_KEY_CULL_DISABLED_FLAG, p_reverse_cull); - state.scene_shader.set_uniform(SceneShaderGLES3::NORMAL_MULT, e->instance->mirror ? -1.0 : 1.0); state.scene_shader.set_uniform(SceneShaderGLES3::WORLD_TRANSFORM, e->instance->transform); _render_geometry(e); @@ -2535,7 +2537,7 @@ void RasterizerSceneGLES3::_draw_sky(RasterizerStorageGLES3::Sky *p_sky, const C storage->shaders.copy.set_conditional(CopyShaderGLES3::USE_PANORAMA, false); } -void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform) { +void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog) { //store camera into ubo store_camera(p_cam_projection, state.ubo_data.projection_matrix); @@ -2586,7 +2588,8 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr state.ubo_data.fog_color_enabled[0] = linear_fog.r; state.ubo_data.fog_color_enabled[1] = linear_fog.g; state.ubo_data.fog_color_enabled[2] = linear_fog.b; - state.ubo_data.fog_color_enabled[3] = env->fog_enabled ? 1.0 : 0.0; + state.ubo_data.fog_color_enabled[3] = (!p_no_fog && env->fog_enabled) ? 1.0 : 0.0; + state.ubo_data.fog_density = linear_fog.a; Color linear_sun = env->fog_sun_color.to_linear(); state.ubo_data.fog_sun_color_amount[0] = linear_sun.r; @@ -2595,6 +2598,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr state.ubo_data.fog_sun_color_amount[3] = env->fog_sun_amount; state.ubo_data.fog_depth_enabled = env->fog_depth_enabled; state.ubo_data.fog_depth_begin = env->fog_depth_begin; + state.ubo_data.fog_depth_end = env->fog_depth_end; state.ubo_data.fog_depth_curve = env->fog_depth_curve; state.ubo_data.fog_transmit_enabled = env->fog_transmit_enabled; state.ubo_data.fog_transmit_curve = env->fog_transmit_curve; @@ -3036,19 +3040,17 @@ void RasterizerSceneGLES3::_setup_reflections(RID *p_reflection_probe_cull_resul reflection_ubo.ambient[3] = rpi->probe_ptr->interior_ambient_probe_contrib; } else { Color ambient_linear; - float contrib = 0; if (p_env) { ambient_linear = p_env->ambient_color.to_linear(); ambient_linear.r *= p_env->ambient_energy; ambient_linear.g *= p_env->ambient_energy; ambient_linear.b *= p_env->ambient_energy; - contrib = p_env->ambient_sky_contribution; } reflection_ubo.ambient[0] = ambient_linear.r; reflection_ubo.ambient[1] = ambient_linear.g; reflection_ubo.ambient[2] = ambient_linear.b; - reflection_ubo.ambient[3] = 0; + reflection_ubo.ambient[3] = 0; //not used in exterior mode, since it just blends with regular ambient light } int cell_size = reflection_atlas->size / reflection_atlas->subdiv; @@ -3209,6 +3211,7 @@ void RasterizerSceneGLES3::_fill_render_list(InstanceBase **p_cull_result, int p } } break; + default: {} } } } @@ -3594,7 +3597,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); } - if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) { + if (!env || storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT] || storage->frame.current_rt->width < 4 || storage->frame.current_rt->height < 4) { //no post process on small render targets //no environment or transparent render, simply return and convert to SRGB glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo); glActiveTexture(GL_TEXTURE0); @@ -3896,6 +3899,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::PIXEL_SIZE, Vector2(1.0 / vp_w, 1.0 / vp_h)); state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LOD, float(i)); state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::GLOW_STRENGTH, env->glow_strength); + state.effect_blur_shader.set_uniform(EffectBlurShaderGLES3::LUMINANCE_CAP, env->glow_hdr_luminance_cap); glActiveTexture(GL_TEXTURE0); if (i == 0) { @@ -3945,7 +3949,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_FILMIC); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_ACES); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINDHART_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_REINHARDT); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, env->tone_mapper == VS::ENV_TONE_MAPPER_REINHARD); state.tonemap_shader.set_conditional(TonemapShaderGLES3::KEEP_3D_LINEAR, storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_KEEP_3D_LINEAR]); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, env->auto_exposure); @@ -4032,7 +4036,7 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_AUTO_EXPOSURE, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_FILMIC_TONEMAPPER, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_ACES_TONEMAPPER, false); - state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINDHART_TONEMAPPER, false); + state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_REINHARD_TONEMAPPER, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL1, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL2, false); state.tonemap_shader.set_conditional(TonemapShaderGLES3::USE_GLOW_LEVEL3, false); @@ -4097,7 +4101,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const state.ubo_data.screen_pixel_size[1] = 1.0 / storage->frame.current_rt->height; } - _setup_environment(env, p_cam_projection, p_cam_transform); + _setup_environment(env, p_cam_projection, p_cam_transform, p_reflection_probe.is_valid()); bool fb_cleared = false; @@ -4292,10 +4296,11 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glClearBufferfv(GL_COLOR, 0, clear_color.components); // specular } + VS::EnvironmentBG bg_mode = (!env || (probe && env->bg_mode == VS::ENV_BG_CANVAS)) ? VS::ENV_BG_CLEAR_COLOR : env->bg_mode; //if no environment, or canvas while rendering a probe (invalid use case), use color. + if (env) { - switch (env->bg_mode) { + switch (bg_mode) { case VS::ENV_BG_COLOR_SKY: - case VS::ENV_BG_SKY: sky = storage->sky_owner.getornull(env->sky); @@ -4333,9 +4338,14 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); break; + default: {} } } + if (probe && probe->probe_ptr->interior) { + env_radiance_tex = 0; //for rendering probe interiors, radiance must not be used. + } + state.texscreen_copied = false; glBlendEquation(GL_FUNC_ADD); @@ -4501,7 +4511,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ RasterizerStorageGLES3::Light *light = storage->light_owner.getornull(light_instance->light); ERR_FAIL_COND(!light); - uint32_t x, y, width, height, vp_height; + uint32_t x, y, width, height; float dp_direction = 0.0; float zfar = 0; @@ -4583,7 +4593,6 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS] * bias_mult; normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] * bias_mult; fbo = directional_shadow.fbo; - vp_height = directional_shadow.size; } else { //set from shadow atlas @@ -4593,7 +4602,6 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_ ERR_FAIL_COND(!shadow_atlas->shadow_owners.has(p_light)); fbo = shadow_atlas->fbo; - vp_height = shadow_atlas->size; uint32_t key = shadow_atlas->shadow_owners[p_light]; @@ -4871,10 +4879,7 @@ void RasterizerSceneGLES3::initialize() { glBindBuffer(GL_UNIFORM_BUFFER, 0); render_list.max_elements = GLOBAL_DEF_RST("rendering/limits/rendering/max_renderable_elements", (int)RenderList::DEFAULT_MAX_ELEMENTS); - if (render_list.max_elements > 1000000) - render_list.max_elements = 1000000; - if (render_list.max_elements < 1024) - render_list.max_elements = 1024; + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/rendering/max_renderable_elements", PropertyInfo(Variant::INT, "rendering/limits/rendering/max_renderable_elements", PROPERTY_HINT_RANGE, "1024,1000000,1")); { //quad buffers @@ -5073,6 +5078,7 @@ void RasterizerSceneGLES3::initialize() { { uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/immediate_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/immediate_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); glGenBuffers(1, &state.immediate_buffer); glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer); diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h index b4c4a0558f..0e6027c4ad 100644 --- a/drivers/gles3/rasterizer_scene_gles3.h +++ b/drivers/gles3/rasterizer_scene_gles3.h @@ -145,6 +145,8 @@ public: uint32_t fog_depth_enabled; float fog_depth_begin; + float fog_depth_end; + float fog_density; float fog_depth_curve; uint32_t fog_transmit_enabled; float fog_transmit_curve; @@ -402,6 +404,7 @@ public: VS::EnvironmentGlowBlendMode glow_blend_mode; float glow_hdr_bleed_threshold; float glow_hdr_bleed_scale; + float glow_hdr_luminance_cap; bool glow_bicubic_upscale; VS::EnvironmentToneMapper tone_mapper; @@ -438,6 +441,7 @@ public: bool fog_depth_enabled; float fog_depth_begin; + float fog_depth_end; float fog_depth_curve; bool fog_transmit_enabled; float fog_transmit_curve; @@ -491,6 +495,7 @@ public: glow_blend_mode = VS::GLOW_BLEND_MODE_SOFTLIGHT; glow_hdr_bleed_threshold = 1.0; glow_hdr_bleed_scale = 2.0; + glow_hdr_luminance_cap = 12.0; glow_bicubic_upscale = false; dof_blur_far_enabled = false; @@ -518,6 +523,7 @@ public: fog_depth_enabled = true; fog_depth_begin = 10; + fog_depth_end = 0; fog_depth_curve = 1; fog_transmit_enabled = true; @@ -544,7 +550,7 @@ public: virtual void environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); virtual void environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality); - virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, bool p_bicubic_upscale); + virtual void environment_set_glow(RID p_env, bool p_enable, int p_level_flags, float p_intensity, float p_strength, float p_bloom_threshold, VS::EnvironmentGlowBlendMode p_blend_mode, float p_hdr_bleed_threshold, float p_hdr_bleed_scale, float p_hdr_luminance_cap, bool p_bicubic_upscale); virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture); virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness); @@ -555,7 +561,7 @@ public: virtual void environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp); virtual void environment_set_fog(RID p_env, bool p_enable, const Color &p_color, const Color &p_sun_color, float p_sun_amount); - virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve); + virtual void environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_end, float p_depth_curve, bool p_transmit, float p_transmit_curve); virtual void environment_set_fog_height(RID p_env, bool p_enable, float p_min_height, float p_max_height, float p_height_curve); virtual bool is_environment(RID p_env); @@ -831,7 +837,7 @@ public: void _draw_sky(RasterizerStorageGLES3::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy); - void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform); + void _setup_environment(Environment *env, const CameraMatrix &p_cam_projection, const Transform &p_cam_transform, bool p_no_fog = false); void _setup_directional_light(int p_index, const Transform &p_camera_inverse_transform, bool p_use_shadows); void _setup_lights(RID *p_light_cull_result, int p_light_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_shadow_atlas); void _setup_reflections(RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, const Transform &p_camera_inverse_transform, const CameraMatrix &p_camera_projection, RID p_reflection_atlas, Environment *p_env); diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp index 25e7bd0424..2b038fcc0e 100644 --- a/drivers/gles3/rasterizer_storage_gles3.cpp +++ b/drivers/gles3/rasterizer_storage_gles3.cpp @@ -101,6 +101,28 @@ #define _EXT_COMPRESSED_RGB_BPTC_SIGNED_FLOAT 0x8E8E #define _EXT_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT 0x8E8F +#ifdef __EMSCRIPTEN__ +#include <emscripten/emscripten.h> + +void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data) { + + /* clang-format off */ + EM_ASM({ + GLctx.getBufferSubData($0, $1, HEAPU8, $2, $3); + }, target, offset, data, size); + /* clang-format on */ +} + +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data) { + + /* clang-format off */ + EM_ASM({ + GLctx.bufferSubData($0, $1, HEAPU8, $2, $3); + }, target, offset, data, size); + /* clang-format on */ +} +#endif + void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLenum format, GLenum type) { #ifdef GLES_OVER_GL @@ -730,7 +752,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p } }; - GLenum blit_target; + GLenum blit_target = GL_TEXTURE_2D; switch (texture->type) { case VS::TEXTURE_TYPE_2D: { @@ -852,8 +874,6 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p int size, ofs; img->get_mipmap_offset_and_size(i, ofs, size); - //print_line("mipmap: "+itos(i)+" size: "+itos(size)+" w: "+itos(mm_w)+", h: "+itos(mm_h)); - if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) { if (texture->compressed) { @@ -948,7 +968,7 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I Image::Format real_format; Ref<Image> img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, real_format, format, internal_format, type, compressed, srgb); - GLenum blit_target; + GLenum blit_target = GL_TEXTURE_2D; switch (texture->type) { case VS::TEXTURE_TYPE_2D: { @@ -1029,7 +1049,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) PoolVector<uint8_t> data; - int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1 ? -1 : 0); + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, texture->mipmaps > 1); data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers PoolVector<uint8_t>::Write wb = data.write(); @@ -1040,8 +1060,6 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) glBindBuffer(GL_PIXEL_PACK_BUFFER, 0); - //print_line("GET FORMAT: " + Image::get_format_name(texture->format) + " mipmaps: " + itos(texture->mipmaps)); - for (int i = 0; i < texture->mipmaps; i++) { int ofs = 0; @@ -1072,7 +1090,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) uint32_t *ptr = (uint32_t *)wb.ptr(); uint32_t num_pixels = data_size / 4; - for (int ofs = 0; ofs < num_pixels; ofs++) { + for (uint32_t ofs = 0; ofs < num_pixels; ofs++) { uint32_t px = ptr[ofs]; uint32_t a = px >> 30 & 0xFF; @@ -1094,8 +1112,76 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) return Ref<Image>(img); #else - ERR_EXPLAIN("Sorry, It's not possible to obtain images back in OpenGL ES"); - ERR_FAIL_V(Ref<Image>()); + Image::Format real_format; + GLenum gl_format; + GLenum gl_internal_format; + GLenum gl_type; + bool compressed; + bool srgb; + _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, gl_format, gl_internal_format, gl_type, compressed, srgb); + + PoolVector<uint8_t> data; + + int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false); + + data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers + PoolVector<uint8_t>::Write wb = data.write(); + + GLuint temp_framebuffer; + glGenFramebuffers(1, &temp_framebuffer); + + GLuint temp_color_texture; + glGenTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer); + + glBindTexture(GL_TEXTURE_2D, temp_color_texture); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0); + + glDepthMask(GL_FALSE); + glDisable(GL_DEPTH_TEST); + glDisable(GL_CULL_FACE); + glDisable(GL_BLEND); + glDepthFunc(GL_LEQUAL); + glColorMask(1, 1, 1, 1); + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture->tex_id); + + glViewport(0, 0, texture->alloc_width, texture->alloc_height); + + shaders.copy.bind(); + + shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, !srgb); + + glClearColor(0.0, 0.0, 0.0, 0.0); + glClear(GL_COLOR_BUFFER_BIT); + glBindVertexArray(resources.quadie_array); + glDrawArrays(GL_TRIANGLE_FAN, 0, 4); + glBindVertexArray(0); + + glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &wb[0]); + + shaders.copy.set_conditional(CopyShaderGLES3::LINEAR_TO_SRGB, false); + + glDeleteTextures(1, &temp_color_texture); + + glBindFramebuffer(GL_FRAMEBUFFER, 0); + glDeleteFramebuffers(1, &temp_framebuffer); + + wb = PoolVector<uint8_t>::Write(); + + data.resize(data_size); + + Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, false, Image::FORMAT_RGBA8, data)); + if (!texture->compressed) { + img->convert(real_format); + } + + return Ref<Image>(img); #endif } @@ -1811,6 +1897,10 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { p_shader->uniforms.clear(); + if (p_shader->code == String()) { + return; //just invalid, but no error + } + ShaderCompilerGLES3::GeneratedCode gen_code; ShaderCompilerGLES3::IdentifierActions *actions = NULL; @@ -1905,6 +1995,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const { actions = &shaders.actions_particles; actions->uniforms = &p_shader->uniforms; } break; + case VS::SHADER_MAX: break; // Can't happen, but silences warning } Error err = shaders.compiler.compile(p_shader->mode, p_shader->code, actions, p_shader->path, gen_code); @@ -2028,6 +2119,14 @@ void RasterizerStorageGLES3::shader_get_param_list(RID p_shader, List<PropertyIn pi.hint = PROPERTY_HINT_RESOURCE_TYPE; pi.hint_string = "Texture"; } break; + case ShaderLanguage::TYPE_SAMPLER2DARRAY: + case ShaderLanguage::TYPE_ISAMPLER2DARRAY: + case ShaderLanguage::TYPE_USAMPLER2DARRAY: { + + pi.type = Variant::OBJECT; + pi.hint = PROPERTY_HINT_RESOURCE_TYPE; + pi.hint_string = "TextureArray"; + } break; case ShaderLanguage::TYPE_SAMPLER3D: case ShaderLanguage::TYPE_ISAMPLER3D: case ShaderLanguage::TYPE_USAMPLER3D: { @@ -2148,8 +2247,9 @@ Variant RasterizerStorageGLES3::material_get_param_default(RID p_material, const if (material->shader) { if (material->shader->uniforms.has(p_param)) { - Vector<ShaderLanguage::ConstantNode::Value> default_value = material->shader->uniforms[p_param].default_value; - return ShaderLanguage::constant_value_to_variant(default_value, material->shader->uniforms[p_param].type); + ShaderLanguage::ShaderNode::Uniform uniform = material->shader->uniforms[p_param]; + Vector<ShaderLanguage::ConstantNode::Value> default_value = uniform.default_value; + return ShaderLanguage::constant_value_to_variant(default_value, uniform.type, uniform.hint); } } return Variant(); @@ -2729,7 +2829,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { if (material->shader && material->shader->mode == VS::SHADER_SPATIAL) { if (material->shader->spatial.blend_mode == Shader::Spatial::BLEND_MODE_MIX && - (!material->shader->spatial.uses_alpha || (material->shader->spatial.uses_alpha && material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS))) { + (!material->shader->spatial.uses_alpha || material->shader->spatial.depth_draw_mode == Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) { can_cast_shadow = true; } @@ -2750,7 +2850,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) { } for (Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.front(); E; E = E->next()) { - E->key()->base_material_changed(); + E->key()->base_changed(false, true); } } } @@ -2786,9 +2886,6 @@ void RasterizerStorageGLES3::_update_material(Material *material) { if (E->get().order < 0) continue; // texture, does not go here - //if (material->shader->mode == VS::SHADER_PARTICLES) { - // print_line("uniform " + String(E->key()) + " order " + itos(E->get().order) + " offset " + itos(material->shader->ubo_offsets[E->get().order])); - //} //regular uniform uint8_t *data = &local_ubo[material->shader->ubo_offsets[E->get().order]]; @@ -3376,7 +3473,7 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS: } mesh->surfaces.push_back(surface); - mesh->instance_change_notify(); + mesh->instance_change_notify(true, false); info.vertex_mem += surface->total_data_size; } @@ -3449,7 +3546,7 @@ void RasterizerStorageGLES3::mesh_surface_set_material(RID p_mesh, int p_surface _material_add_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]); } - mesh->instance_material_change_notify(); + mesh->instance_change_notify(false, true); } RID RasterizerStorageGLES3::mesh_surface_get_material(RID p_mesh, int p_surface) const { @@ -3485,21 +3582,26 @@ PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_array(RID p_mesh, i Surface *surface = mesh->surfaces[p_surface]; - glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); - void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, surface->array_byte_size, GL_MAP_READ_BIT); - - ERR_FAIL_COND_V(!data, PoolVector<uint8_t>()); - PoolVector<uint8_t> ret; ret.resize(surface->array_byte_size); + glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id); +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + { + PoolVector<uint8_t>::Write w = ret.write(); + glGetBufferSubData(GL_ARRAY_BUFFER, 0, surface->array_byte_size, w.ptr()); + } +#else + void *data = glMapBufferRange(GL_ARRAY_BUFFER, 0, surface->array_byte_size, GL_MAP_READ_BIT); + ERR_FAIL_NULL_V(data, PoolVector<uint8_t>()); { - PoolVector<uint8_t>::Write w = ret.write(); copymem(w.ptr(), data, surface->array_byte_size); } glUnmapBuffer(GL_ARRAY_BUFFER); +#endif + glBindBuffer(GL_ARRAY_BUFFER, 0); return ret; } @@ -3512,22 +3614,26 @@ PoolVector<uint8_t> RasterizerStorageGLES3::mesh_surface_get_index_array(RID p_m ERR_FAIL_COND_V(surface->index_array_len == 0, PoolVector<uint8_t>()); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); - void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT); - - ERR_FAIL_COND_V(!data, PoolVector<uint8_t>()); - PoolVector<uint8_t> ret; ret.resize(surface->index_array_byte_size); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id); +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + { + PoolVector<uint8_t>::Write w = ret.write(); + glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, w.ptr()); + } +#else + void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, surface->index_array_byte_size, GL_MAP_READ_BIT); + ERR_FAIL_NULL_V(data, PoolVector<uint8_t>()); { - PoolVector<uint8_t>::Write w = ret.write(); copymem(w.ptr(), data, surface->index_array_byte_size); } - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); +#endif + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); return ret; } @@ -3568,23 +3674,26 @@ Vector<PoolVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shap for (int i = 0; i < mesh->surfaces[p_surface]->blend_shapes.size(); i++) { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->surfaces[p_surface]->blend_shapes[i].vertex_id); - void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, GL_MAP_READ_BIT); - - ERR_FAIL_COND_V(!data, Vector<PoolVector<uint8_t> >()); - PoolVector<uint8_t> ret; ret.resize(mesh->surfaces[p_surface]->array_byte_size); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, mesh->surfaces[p_surface]->blend_shapes[i].vertex_id); +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + { + PoolVector<uint8_t>::Write w = ret.write(); + glGetBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, w.ptr()); + } +#else + void *data = glMapBufferRange(GL_ELEMENT_ARRAY_BUFFER, 0, mesh->surfaces[p_surface]->array_byte_size, GL_MAP_READ_BIT); + ERR_FAIL_COND_V(!data, Vector<PoolVector<uint8_t> >()); { - PoolVector<uint8_t>::Write w = ret.write(); copymem(w.ptr(), data, mesh->surfaces[p_surface]->array_byte_size); } + glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); +#endif bsarr.push_back(ret); - - glUnmapBuffer(GL_ELEMENT_ARRAY_BUFFER); } return bsarr; @@ -3633,13 +3742,11 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface) { info.vertex_mem -= surface->total_data_size; - mesh->instance_material_change_notify(); - memdelete(surface); mesh->surfaces.remove(p_surface); - mesh->instance_change_notify(); + mesh->instance_change_notify(true, true); } int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const { @@ -3655,7 +3762,7 @@ void RasterizerStorageGLES3::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb ERR_FAIL_COND(!mesh); mesh->custom_aabb = p_aabb; - mesh->instance_change_notify(); + mesh->instance_change_notify(true, false); } AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const { @@ -3671,12 +3778,14 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { Mesh *mesh = mesh_owner.get(p_mesh); ERR_FAIL_COND_V(!mesh, AABB()); - if (mesh->custom_aabb != AABB()) + if (mesh->custom_aabb != AABB()) { return mesh->custom_aabb; + } Skeleton *sk = NULL; - if (p_skeleton.is_valid()) + if (p_skeleton.is_valid()) { sk = skeleton_owner.get(p_skeleton); + } AABB aabb; @@ -3715,6 +3824,7 @@ AABB RasterizerStorageGLES3::mesh_get_aabb(RID p_mesh, RID p_skeleton) const { mtx.origin.y = texture[base_ofs + 3]; AABB baabb = mtx.xform(skbones[j]); + if (first) { laabb = baabb; first = false; @@ -4057,35 +4167,37 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances multimesh->data.resize(format_floats * p_instances); + float *dataptr = multimesh->data.ptrw(); + for (int i = 0; i < p_instances * format_floats; i += format_floats) { int color_from = 0; int custom_data_from = 0; if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) { - multimesh->data.write[i + 0] = 1.0; - multimesh->data.write[i + 1] = 0.0; - multimesh->data.write[i + 2] = 0.0; - multimesh->data.write[i + 3] = 0.0; - multimesh->data.write[i + 4] = 0.0; - multimesh->data.write[i + 5] = 1.0; - multimesh->data.write[i + 6] = 0.0; - multimesh->data.write[i + 7] = 0.0; + dataptr[i + 0] = 1.0; + dataptr[i + 1] = 0.0; + dataptr[i + 2] = 0.0; + dataptr[i + 3] = 0.0; + dataptr[i + 4] = 0.0; + dataptr[i + 5] = 1.0; + dataptr[i + 6] = 0.0; + dataptr[i + 7] = 0.0; color_from = 8; custom_data_from = 8; } else { - multimesh->data.write[i + 0] = 1.0; - multimesh->data.write[i + 1] = 0.0; - multimesh->data.write[i + 2] = 0.0; - multimesh->data.write[i + 3] = 0.0; - multimesh->data.write[i + 4] = 0.0; - multimesh->data.write[i + 5] = 1.0; - multimesh->data.write[i + 6] = 0.0; - multimesh->data.write[i + 7] = 0.0; - multimesh->data.write[i + 8] = 0.0; - multimesh->data.write[i + 9] = 0.0; - multimesh->data.write[i + 10] = 1.0; - multimesh->data.write[i + 11] = 0.0; + dataptr[i + 0] = 1.0; + dataptr[i + 1] = 0.0; + dataptr[i + 2] = 0.0; + dataptr[i + 3] = 0.0; + dataptr[i + 4] = 0.0; + dataptr[i + 5] = 1.0; + dataptr[i + 6] = 0.0; + dataptr[i + 7] = 0.0; + dataptr[i + 8] = 0.0; + dataptr[i + 9] = 0.0; + dataptr[i + 10] = 1.0; + dataptr[i + 11] = 0.0; color_from = 12; custom_data_from = 12; } @@ -4100,14 +4212,14 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances } cu; cu.colu = 0xFFFFFFFF; - multimesh->data.write[i + color_from + 0] = cu.colf; + dataptr[i + color_from + 0] = cu.colf; custom_data_from = color_from + 1; } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) { - multimesh->data.write[i + color_from + 0] = 1.0; - multimesh->data.write[i + color_from + 1] = 1.0; - multimesh->data.write[i + color_from + 2] = 1.0; - multimesh->data.write[i + color_from + 3] = 1.0; + dataptr[i + color_from + 0] = 1.0; + dataptr[i + color_from + 1] = 1.0; + dataptr[i + color_from + 2] = 1.0; + dataptr[i + color_from + 3] = 1.0; custom_data_from = color_from + 4; } @@ -4121,13 +4233,13 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances } cu; cu.colu = 0; - multimesh->data.write[i + custom_data_from + 0] = cu.colf; + dataptr[i + custom_data_from + 0] = cu.colf; } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) { - multimesh->data.write[i + custom_data_from + 0] = 0.0; - multimesh->data.write[i + custom_data_from + 1] = 0.0; - multimesh->data.write[i + custom_data_from + 2] = 0.0; - multimesh->data.write[i + custom_data_from + 3] = 0.0; + dataptr[i + custom_data_from + 0] = 0.0; + dataptr[i + custom_data_from + 1] = 0.0; + dataptr[i + custom_data_from + 2] = 0.0; + dataptr[i + custom_data_from + 3] = 0.0; } } @@ -4552,7 +4664,7 @@ void RasterizerStorageGLES3::update_dirty_multimeshes() { multimesh->dirty_aabb = false; multimesh->dirty_data = false; - multimesh->instance_change_notify(); + multimesh->instance_change_notify(true, false); multimesh_update_list.remove(multimesh_update_list.first()); } @@ -4663,7 +4775,7 @@ void RasterizerStorageGLES3::immediate_end(RID p_immediate) { im->building = false; - im->instance_change_notify(); + im->instance_change_notify(true, false); } void RasterizerStorageGLES3::immediate_clear(RID p_immediate) { @@ -4672,7 +4784,7 @@ void RasterizerStorageGLES3::immediate_clear(RID p_immediate) { ERR_FAIL_COND(im->building); im->chunks.clear(); - im->instance_change_notify(); + im->instance_change_notify(true, false); } AABB RasterizerStorageGLES3::immediate_get_aabb(RID p_immediate) const { @@ -4687,7 +4799,7 @@ void RasterizerStorageGLES3::immediate_set_material(RID p_immediate, RID p_mater Immediate *im = immediate_owner.get(p_immediate); ERR_FAIL_COND(!im); im->material = p_material; - im->instance_material_change_notify(); + im->instance_change_notify(false, true); } RID RasterizerStorageGLES3::immediate_get_material(RID p_immediate) const { @@ -4893,7 +5005,7 @@ void RasterizerStorageGLES3::update_dirty_skeletons() { } for (Set<RasterizerScene::InstanceBase *>::Element *E = skeleton->instances.front(); E; E = E->next()) { - E->get()->base_changed(); + E->get()->base_changed(true, false); } skeleton_update_list.remove(skeleton_update_list.first()); @@ -4959,8 +5071,9 @@ void RasterizerStorageGLES3::light_set_param(RID p_light, VS::LightParam p_param case VS::LIGHT_PARAM_SHADOW_BIAS: { light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } break; + default: {} } light->param[p_param] = p_value; @@ -4972,7 +5085,7 @@ void RasterizerStorageGLES3::light_set_shadow(RID p_light, bool p_enabled) { light->shadow = p_enabled; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_set_shadow_color(RID p_light, const Color &p_color) { @@ -5005,7 +5118,7 @@ void RasterizerStorageGLES3::light_set_cull_mask(RID p_light, uint32_t p_mask) { light->cull_mask = p_mask; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) { @@ -5014,6 +5127,9 @@ void RasterizerStorageGLES3::light_set_reverse_cull_face_mode(RID p_light, bool ERR_FAIL_COND(!light); light->reverse_cull = p_enabled; + + light->version++; + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) { @@ -5024,7 +5140,7 @@ void RasterizerStorageGLES3::light_omni_set_shadow_mode(RID p_light, VS::LightOm light->omni_shadow_mode = p_mode; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } VS::LightOmniShadowMode RasterizerStorageGLES3::light_omni_get_shadow_mode(RID p_light) { @@ -5042,7 +5158,7 @@ void RasterizerStorageGLES3::light_omni_set_shadow_detail(RID p_light, VS::Light light->omni_shadow_detail = p_detail; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) { @@ -5052,7 +5168,7 @@ void RasterizerStorageGLES3::light_directional_set_shadow_mode(RID p_light, VS:: light->directional_shadow_mode = p_mode; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } void RasterizerStorageGLES3::light_directional_set_blend_splits(RID p_light, bool p_enable) { @@ -5062,7 +5178,7 @@ void RasterizerStorageGLES3::light_directional_set_blend_splits(RID p_light, boo light->directional_blend_splits = p_enable; light->version++; - light->instance_change_notify(); + light->instance_change_notify(true, false); } bool RasterizerStorageGLES3::light_directional_get_blend_splits(RID p_light) const { @@ -5193,7 +5309,7 @@ void RasterizerStorageGLES3::reflection_probe_set_update_mode(RID p_probe, VS::R ERR_FAIL_COND(!reflection_probe); reflection_probe->update_mode = p_mode; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_intensity(RID p_probe, float p_intensity) { @@ -5234,7 +5350,7 @@ void RasterizerStorageGLES3::reflection_probe_set_max_distance(RID p_probe, floa ERR_FAIL_COND(!reflection_probe); reflection_probe->max_distance = p_distance; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vector3 &p_extents) { @@ -5242,7 +5358,7 @@ void RasterizerStorageGLES3::reflection_probe_set_extents(RID p_probe, const Vec ERR_FAIL_COND(!reflection_probe); reflection_probe->extents = p_extents; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, const Vector3 &p_offset) { @@ -5250,7 +5366,7 @@ void RasterizerStorageGLES3::reflection_probe_set_origin_offset(RID p_probe, con ERR_FAIL_COND(!reflection_probe); reflection_probe->origin_offset = p_offset; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_as_interior(RID p_probe, bool p_enable) { @@ -5274,7 +5390,7 @@ void RasterizerStorageGLES3::reflection_probe_set_enable_shadows(RID p_probe, bo ERR_FAIL_COND(!reflection_probe); reflection_probe->enable_shadows = p_enable; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); } void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers) { @@ -5282,7 +5398,10 @@ void RasterizerStorageGLES3::reflection_probe_set_cull_mask(RID p_probe, uint32_ ERR_FAIL_COND(!reflection_probe); reflection_probe->cull_mask = p_layers; - reflection_probe->instance_change_notify(); + reflection_probe->instance_change_notify(true, false); +} + +void RasterizerStorageGLES3::reflection_probe_set_resolution(RID p_probe, int p_resolution) { } AABB RasterizerStorageGLES3::reflection_probe_get_aabb(RID p_probe) const { @@ -5367,7 +5486,7 @@ void RasterizerStorageGLES3::gi_probe_set_bounds(RID p_probe, const AABB &p_boun gip->bounds = p_bounds; gip->version++; - gip->instance_change_notify(); + gip->instance_change_notify(true, false); } AABB RasterizerStorageGLES3::gi_probe_get_bounds(RID p_probe) const { @@ -5384,7 +5503,7 @@ void RasterizerStorageGLES3::gi_probe_set_cell_size(RID p_probe, float p_size) { gip->cell_size = p_size; gip->version++; - gip->instance_change_notify(); + gip->instance_change_notify(true, false); } float RasterizerStorageGLES3::gi_probe_get_cell_size(RID p_probe) const { @@ -5417,7 +5536,7 @@ void RasterizerStorageGLES3::gi_probe_set_dynamic_data(RID p_probe, const PoolVe gip->dynamic_data = p_data; gip->version++; - gip->instance_change_notify(); + gip->instance_change_notify(true, false); } PoolVector<int> RasterizerStorageGLES3::gi_probe_get_dynamic_data(RID p_probe) const { @@ -5649,7 +5768,7 @@ void RasterizerStorageGLES3::lightmap_capture_set_bounds(RID p_capture, const AA LightmapCapture *capture = lightmap_capture_data_owner.getornull(p_capture); ERR_FAIL_COND(!capture); capture->bounds = p_bounds; - capture->instance_change_notify(); + capture->instance_change_notify(true, false); } AABB RasterizerStorageGLES3::lightmap_capture_get_bounds(RID p_capture) const { @@ -5670,7 +5789,7 @@ void RasterizerStorageGLES3::lightmap_capture_set_octree(RID p_capture, const Po PoolVector<uint8_t>::Read r = p_octree.read(); copymem(w.ptr(), r.ptr(), p_octree.size()); } - capture->instance_change_notify(); + capture->instance_change_notify(true, false); } PoolVector<uint8_t> RasterizerStorageGLES3::lightmap_capture_get_octree(RID p_capture) const { @@ -5893,7 +6012,7 @@ void RasterizerStorageGLES3::particles_set_custom_aabb(RID p_particles, const AA ERR_FAIL_COND(!particles); particles->custom_aabb = p_aabb; _particles_update_histories(particles); - particles->instance_change_notify(); + particles->instance_change_notify(true, false); } void RasterizerStorageGLES3::particles_set_speed_scale(RID p_particles, float p_scale) { @@ -5983,9 +6102,21 @@ AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { const Particles *particles = particles_owner.getornull(p_particles); ERR_FAIL_COND_V(!particles, AABB()); + const float *data; glBindBuffer(GL_ARRAY_BUFFER, particles->particle_buffers[0]); - float *data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT); +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + PoolVector<uint8_t> vector; + vector.resize(particles->amount * 16 * 6); + { + PoolVector<uint8_t>::Write w = vector.write(); + glGetBufferSubData(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, w.ptr()); + } + PoolVector<uint8_t>::Read r = vector.read(); + data = reinterpret_cast<const float *>(r.ptr()); +#else + data = (float *)glMapBufferRange(GL_ARRAY_BUFFER, 0, particles->amount * 16 * 6, GL_MAP_READ_BIT); +#endif AABB aabb; Transform inv = particles->emission_transform.affine_inverse(); @@ -6002,7 +6133,13 @@ AABB RasterizerStorageGLES3::particles_get_current_aabb(RID p_particles) { aabb.expand_to(pos); } +#if defined(GLES_OVER_GL) || defined(__EMSCRIPTEN__) + r = PoolVector<uint8_t>::Read(); + vector = PoolVector<uint8_t>(); +#else glUnmapBuffer(GL_ARRAY_BUFFER); +#endif + glBindBuffer(GL_ARRAY_BUFFER, 0); float longest_axis = 0; @@ -6301,12 +6438,19 @@ void RasterizerStorageGLES3::update_particles() { particles->particle_valid_histories[0] = true; } - particles->instance_change_notify(); //make sure shadows are updated + particles->instance_change_notify(true, false); //make sure shadows are updated } glDisable(GL_RASTERIZER_DISCARD); } +bool RasterizerStorageGLES3::particles_is_inactive(RID p_particles) const { + + const Particles *particles = particles_owner.getornull(p_particles); + ERR_FAIL_COND_V(!particles, false); + return !particles->emitting && particles->inactive; +} + //////// void RasterizerStorageGLES3::instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance) { @@ -6825,7 +6969,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) { glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, level); glDisable(GL_SCISSOR_TEST); glColorMask(1, 1, 1, 1); - if (rt->buffers.active == false) { + if (!rt->buffers.active) { glDepthMask(GL_TRUE); } @@ -7351,7 +7495,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) { GIProbeData *gi_probe_data = gi_probe_data_owner.get(p_rid); glDeleteTextures(1, &gi_probe_data->tex_id); - gi_probe_owner.free(p_rid); + gi_probe_data_owner.free(p_rid); memdelete(gi_probe_data); } else if (lightmap_capture_data_owner.owns(p_rid)) { @@ -7359,7 +7503,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) { LightmapCapture *lightmap_capture = lightmap_capture_data_owner.get(p_rid); lightmap_capture->instance_remove_deps(); - gi_probe_owner.free(p_rid); + lightmap_capture_data_owner.free(p_rid); memdelete(lightmap_capture); } else if (canvas_occluder_owner.owns(p_rid)) { @@ -7529,7 +7673,7 @@ void RasterizerStorageGLES3::initialize() { config.etc2_supported = true; config.hdr_supported = false; config.s3tc_supported = config.extensions.has("GL_EXT_texture_compression_dxt1") || config.extensions.has("GL_EXT_texture_compression_s3tc") || config.extensions.has("WEBGL_compressed_texture_s3tc"); - config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc"); + config.rgtc_supported = config.extensions.has("GL_EXT_texture_compression_rgtc") || config.extensions.has("GL_ARB_texture_compression_rgtc") || config.extensions.has("EXT_texture_compression_rgtc"); #endif config.pvrtc_supported = config.extensions.has("GL_IMG_texture_compression_pvrtc"); @@ -7668,6 +7812,8 @@ void RasterizerStorageGLES3::initialize() { { //transform feedback buffers uint32_t xf_feedback_size = GLOBAL_DEF_RST("rendering/limits/buffers/blend_shape_max_buffer_size_kb", 4096); + ProjectSettings::get_singleton()->set_custom_property_info("rendering/limits/buffers/blend_shape_max_buffer_size_kb", PropertyInfo(Variant::INT, "rendering/limits/buffers/blend_shape_max_buffer_size_kb", PROPERTY_HINT_RANGE, "0,8192,1,or_greater")); + for (int i = 0; i < 2; i++) { glGenBuffers(1, &resources.transform_feedback_buffers[i]); diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h index 0bd9c22be5..398ffdeb82 100644 --- a/drivers/gles3/rasterizer_storage_gles3.h +++ b/drivers/gles3/rasterizer_storage_gles3.h @@ -43,6 +43,12 @@ #include "shaders/cubemap_filter.glsl.gen.h" #include "shaders/particles.glsl.gen.h" +// WebGL 2.0 has no MapBufferRange/UnmapBuffer, but offers a non-ES style BufferSubData API instead. +#ifdef __EMSCRIPTEN__ +void glGetBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, GLvoid *data); +void glBufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const GLvoid *data); +#endif + class RasterizerCanvasGLES3; class RasterizerSceneGLES3; @@ -175,22 +181,12 @@ public: SelfList<RasterizerScene::InstanceBase>::List instance_list; - _FORCE_INLINE_ void instance_change_notify() { + _FORCE_INLINE_ void instance_change_notify(bool p_aabb, bool p_materials) { SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); while (instances) { - instances->self()->base_changed(); - instances = instances->next(); - } - } - - _FORCE_INLINE_ void instance_material_change_notify() { - - SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first(); - while (instances) { - - instances->self()->base_material_changed(); + instances->self()->base_changed(p_aabb, p_materials); instances = instances->next(); } } @@ -443,6 +439,7 @@ public: }; int light_mode; + bool uses_screen_texture; bool uses_screen_uv; bool uses_time; @@ -658,7 +655,7 @@ public: bool active; virtual void material_changed_notify() { - mesh->instance_material_change_notify(); + mesh->instance_change_notify(false, true); mesh->update_multimeshes(); } @@ -691,7 +688,7 @@ public: } }; - class MultiMesh; + struct MultiMesh; struct Mesh : public GeometryOwner { @@ -706,7 +703,7 @@ public: SelfList<MultiMesh> *mm = multimeshes.first(); while (mm) { - mm->self()->instance_material_change_notify(); + mm->self()->instance_change_notify(false, true); mm = mm->next(); } } @@ -1005,6 +1002,7 @@ public: virtual void reflection_probe_set_enable_box_projection(RID p_probe, bool p_enable); virtual void reflection_probe_set_enable_shadows(RID p_probe, bool p_enable); virtual void reflection_probe_set_cull_mask(RID p_probe, uint32_t p_layers); + virtual void reflection_probe_set_resolution(RID p_probe, int p_resolution); virtual AABB reflection_probe_get_aabb(RID p_probe) const; virtual VS::ReflectionProbeUpdateMode reflection_probe_get_update_mode(RID p_probe) const; @@ -1263,6 +1261,8 @@ public: virtual int particles_get_draw_passes(RID p_particles) const; virtual RID particles_get_draw_pass_mesh(RID p_particles, int p_pass) const; + virtual bool particles_is_inactive(RID p_particles) const; + /* INSTANCE */ virtual void instance_add_skeleton(RID p_skeleton, RasterizerScene::InstanceBase *p_instance); diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp index 350107de69..adb145711d 100644 --- a/drivers/gles3/shader_compiler_gles3.cpp +++ b/drivers/gles3/shader_compiler_gles3.cpp @@ -79,6 +79,12 @@ static int _get_datatype_size(SL::DataType p_type) { case SL::TYPE_SAMPLER2D: return 16; case SL::TYPE_ISAMPLER2D: return 16; case SL::TYPE_USAMPLER2D: return 16; + case SL::TYPE_SAMPLER2DARRAY: return 16; + case SL::TYPE_ISAMPLER2DARRAY: return 16; + case SL::TYPE_USAMPLER2DARRAY: return 16; + case SL::TYPE_SAMPLER3D: return 16; + case SL::TYPE_ISAMPLER3D: return 16; + case SL::TYPE_USAMPLER3D: return 16; case SL::TYPE_SAMPLERCUBE: return 16; } @@ -112,6 +118,12 @@ static int _get_datatype_alignment(SL::DataType p_type) { case SL::TYPE_SAMPLER2D: return 16; case SL::TYPE_ISAMPLER2D: return 16; case SL::TYPE_USAMPLER2D: return 16; + case SL::TYPE_SAMPLER2DARRAY: return 16; + case SL::TYPE_ISAMPLER2DARRAY: return 16; + case SL::TYPE_USAMPLER2DARRAY: return 16; + case SL::TYPE_SAMPLER3D: return 16; + case SL::TYPE_ISAMPLER3D: return 16; + case SL::TYPE_USAMPLER3D: return 16; case SL::TYPE_SAMPLERCUBE: return 16; } @@ -121,8 +133,7 @@ static String _interpstr(SL::DataInterpolation p_interp) { switch (p_interp) { case SL::INTERPOLATION_FLAT: return "flat "; - case SL::INTERPOLATION_NO_PERSPECTIVE: return "noperspective "; - case SL::INTERPOLATION_SMOOTH: return "smooth "; + case SL::INTERPOLATION_SMOOTH: return ""; } return ""; } @@ -155,15 +166,17 @@ static String _opstr(SL::Operator p_op) { static String _mkid(const String &p_id) { - return "m_" + p_id; + String id = "m_" + p_id; + return id.replace("__", "_dus_"); //doubleunderscore is reserverd in glsl } static String f2sp0(float p_float) { - if (int(p_float) == p_float) - return itos(p_float) + ".0"; - else - return rtoss(p_float); + String num = rtoss(p_float); + if (num.find(".") == -1 && num.find("e") == -1) { + num += ".0"; + } + return num; } static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNode::Value> &p_values) { @@ -216,7 +229,7 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNo text += ")"; return text; } break; - case SL::TYPE_FLOAT: return f2sp0(p_values[0].real) + "f"; + case SL::TYPE_FLOAT: return f2sp0(p_values[0].real); case SL::TYPE_VEC2: case SL::TYPE_VEC3: case SL::TYPE_VEC4: { @@ -464,6 +477,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener //code for functions for (int i = 0; i < pnode->functions.size(); i++) { SL::FunctionNode *fnode = pnode->functions[i].function; + current_func_name = fnode->name; function_code[fnode->name] = _dump_node_code(fnode->body, p_level + 1, r_gen_code, p_actions, p_default_actions, p_assigning); } @@ -860,6 +874,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv"; actions[VS::SHADER_SPATIAL].renames["SCREEN_TEXTURE"] = "screen_texture"; actions[VS::SHADER_SPATIAL].renames["DEPTH_TEXTURE"] = "depth_buffer"; + actions[VS::SHADER_SPATIAL].renames["DEPTH"] = "gl_FragDepth"; actions[VS::SHADER_SPATIAL].renames["ALPHA_SCISSOR"] = "alpha_scissor"; actions[VS::SHADER_SPATIAL].renames["OUTPUT_IS_SRGB"] = "SHADER_IS_SRGB"; @@ -933,7 +948,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() { actions[VS::SHADER_PARTICLES].renames["COLOR"] = "out_color"; actions[VS::SHADER_PARTICLES].renames["VELOCITY"] = "out_velocity_active.xyz"; actions[VS::SHADER_PARTICLES].renames["MASS"] = "mass"; - actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "active"; + actions[VS::SHADER_PARTICLES].renames["ACTIVE"] = "shader_active"; actions[VS::SHADER_PARTICLES].renames["RESTART"] = "restart"; actions[VS::SHADER_PARTICLES].renames["CUSTOM"] = "out_custom"; actions[VS::SHADER_PARTICLES].renames["TRANSFORM"] = "xform"; diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp index 799179e8d4..404a9107ab 100644 --- a/drivers/gles3/shader_gles3.cpp +++ b/drivers/gles3/shader_gles3.cpp @@ -219,20 +219,15 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { strings.push_back("#version 300 es\n"); #endif - int define_line_ofs = 1; - for (int i = 0; i < custom_defines.size(); i++) { strings.push_back(custom_defines[i].get_data()); - define_line_ofs++; } for (int j = 0; j < conditional_count; j++) { bool enable = ((1 << j) & conditional_version.version); strings.push_back(enable ? conditional_defines[j] : ""); - if (enable) - define_line_ofs++; if (enable) { DEBUG_PRINT(conditional_defines[j]); @@ -253,7 +248,6 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() { ERR_FAIL_COND_V(!custom_code_map.has(conditional_version.code_version), NULL); cc = &custom_code_map[conditional_version.code_version]; v.code_version = cc->version; - define_line_ofs += 2; } /* CREATE PROGRAM */ diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h index 9db4942163..0d360e8453 100644 --- a/drivers/gles3/shader_gles3.h +++ b/drivers/gles3/shader_gles3.h @@ -128,11 +128,13 @@ private: Vector<GLint> texture_uniform_locations; uint32_t code_version; bool ok; - Version() { - code_version = 0; - ok = false; - uniform_location = NULL; - } + Version() : + id(0), + vert_id(0), + frag_id(0), + uniform_location(NULL), + code_version(0), + ok(false) {} }; Version *version; diff --git a/drivers/gles3/shaders/SCsub b/drivers/gles3/shaders/SCsub index f1811fa7b5..27fd1514e7 100644 --- a/drivers/gles3/shaders/SCsub +++ b/drivers/gles3/shaders/SCsub @@ -20,3 +20,4 @@ if 'GLES3_GLSL' in env['BUILDERS']: env.GLES3_GLSL('exposure.glsl'); env.GLES3_GLSL('tonemap.glsl'); env.GLES3_GLSL('particles.glsl'); + env.GLES3_GLSL('lens_distorted.glsl'); diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl index 5203f53fa2..51a4edd233 100644 --- a/drivers/gles3/shaders/canvas.glsl +++ b/drivers/gles3/shaders/canvas.glsl @@ -92,11 +92,6 @@ const bool at_light_pass = true; const bool at_light_pass = false; #endif -#ifdef USE_PARTICLES -uniform int h_frames; -uniform int v_frames; -#endif - #if defined(USE_MATERIAL) /* clang-format off */ @@ -146,15 +141,6 @@ void main() { #ifdef USE_PARTICLES //scale by texture size outvec.xy /= color_texpixel_size; - - //compute h and v frames and adjust UV interp for animation - int total_frames = h_frames * v_frames; - int frame = min(int(float(total_frames) * instance_custom.z), total_frames - 1); - float frame_w = 1.0 / float(h_frames); - float frame_h = 1.0 / float(v_frames); - uv_interp.x = uv_interp.x * frame_w + frame_w * float(frame % h_frames); - uv_interp.y = uv_interp.y * frame_h + frame_h * float(frame / h_frames); - #endif #define extra_matrix extra_matrix_instance @@ -182,7 +168,6 @@ VERTEX_SHADER_CODE color_interp = color; #ifdef USE_PIXEL_SNAP - outvec.xy = floor(outvec + 0.5).xy; #endif @@ -492,6 +477,7 @@ void main() { #if defined(NORMALMAP_USED) vec3 normal_map = vec3(0.0, 0.0, 1.0); + normal_used = true; #endif /* clang-format off */ diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl index b67d06bc10..fc15ca31b1 100644 --- a/drivers/gles3/shaders/effect_blur.glsl +++ b/drivers/gles3/shaders/effect_blur.glsl @@ -94,6 +94,7 @@ uniform sampler2D source_dof_original; //texunit:2 uniform float exposure; uniform float white; +uniform highp float luminance_cap; #ifdef GLOW_USE_AUTO_EXPOSURE @@ -271,7 +272,7 @@ void main() { float luminance = max(frag_color.r, max(frag_color.g, frag_color.b)); float feedback = max(smoothstep(glow_hdr_threshold, glow_hdr_threshold + glow_hdr_scale, luminance), glow_bloom); - frag_color *= feedback; + frag_color = min(frag_color * feedback, vec4(luminance_cap)); #endif diff --git a/drivers/gles3/shaders/lens_distorted.glsl b/drivers/gles3/shaders/lens_distorted.glsl new file mode 100644 index 0000000000..7b9d0b347f --- /dev/null +++ b/drivers/gles3/shaders/lens_distorted.glsl @@ -0,0 +1,64 @@ +/* clang-format off */ +[vertex] + +layout(location = 0) in highp vec4 vertex_attrib; +/* clang-format on */ + +uniform vec2 offset; +uniform vec2 scale; + +out vec2 uv_interp; + +void main() { + + uv_interp = vertex_attrib.xy * 2.0 - 1.0; + + vec2 v = vertex_attrib.xy * scale + offset; + gl_Position = vec4(v, 0.0, 1.0); +} + +/* clang-format off */ +[fragment] + +uniform sampler2D source; //texunit:0 +/* clang-format on */ + +uniform vec2 eye_center; +uniform float k1; +uniform float k2; +uniform float upscale; +uniform float aspect_ratio; + +in vec2 uv_interp; + +layout(location = 0) out vec4 frag_color; + +void main() { + vec2 coords = uv_interp; + vec2 offset = coords - eye_center; + + // take aspect ratio into account + offset.y /= aspect_ratio; + + // distort + vec2 offset_sq = offset * offset; + float radius_sq = offset_sq.x + offset_sq.y; + float radius_s4 = radius_sq * radius_sq; + float distortion_scale = 1.0 + (k1 * radius_sq) + (k2 * radius_s4); + offset *= distortion_scale; + + // reapply aspect ratio + offset.y *= aspect_ratio; + + // add our eye center back in + coords = offset + eye_center; + coords /= upscale; + + // and check our color + if (coords.x < -1.0 || coords.y < -1.0 || coords.x > 1.0 || coords.y > 1.0) { + frag_color = vec4(0.0, 0.0, 0.0, 1.0); + } else { + coords = (coords + vec2(1.0)) / vec2(2.0); + frag_color = textureLod(source, coords, 0.0); + } +} diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl index 7da20dfa00..407e7ec591 100644 --- a/drivers/gles3/shaders/scene.glsl +++ b/drivers/gles3/shaders/scene.glsl @@ -42,8 +42,6 @@ layout(location = 4) in vec2 uv_attrib; layout(location = 5) in vec2 uv2_attrib; #endif -uniform float normal_mult; - #ifdef USE_SKELETON layout(location = 6) in uvec4 bone_indices; // attrib:6 layout(location = 7) in vec4 bone_weights; // attrib:7 @@ -98,6 +96,8 @@ layout(std140) uniform SceneData { // ubo:0 bool fog_depth_enabled; highp float fog_depth_begin; + highp float fog_depth_end; + mediump float fog_density; highp float fog_depth_curve; bool fog_transmit_enabled; highp float fog_transmit_curve; @@ -278,11 +278,10 @@ void main() { } #endif - vec3 normal = normal_attrib * normal_mult; + vec3 normal = normal_attrib; #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) vec3 tangent = tangent_attrib.xyz; - tangent *= normal_mult; float binormalf = tangent_attrib.a; #endif @@ -675,6 +674,8 @@ layout(std140) uniform SceneData { bool fog_depth_enabled; highp float fog_depth_begin; + highp float fog_depth_end; + mediump float fog_density; highp float fog_depth_curve; bool fog_transmit_enabled; highp float fog_transmit_curve; @@ -920,13 +921,14 @@ float GTR1(float NdotH, float a) { return (a2 - 1.0) / (M_PI * log(a2) * t); } -vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) { - float dielectric = (0.034 * 2.0) * specular; - // energy conservation - return mix(vec3(dielectric), albedo, metallic); // TODO: reference? +vec3 F0(float metallic, float specular, vec3 albedo) { + float dielectric = 0.16 * specular * specular; + // use albedo * metallic as colored specular reflectance at 0 angle for metallic materials; + // see https://google.github.io/filament/Filament.md.html + return mix(vec3(dielectric), albedo, vec3(metallic)); } -void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light) { #if defined(USE_LIGHT_SHADER_CODE) // light is written by the light shader @@ -948,6 +950,18 @@ LIGHT_SHADER_CODE float NdotV = dot(N, V); float cNdotV = max(NdotV, 0.0); +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + vec3 H = normalize(V + L); +#endif + +#if defined(SPECULAR_BLINN) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cNdotH = max(dot(N, H), 0.0); +#endif + +#if defined(DIFFUSE_BURLEY) || defined(SPECULAR_SCHLICK_GGX) || defined(LIGHT_USE_CLEARCOAT) + float cLdotH = max(dot(L, H), 0.0); +#endif + if (metallic < 1.0) { #if defined(DIFFUSE_OREN_NAYAR) vec3 diffuse_brdf_NL; @@ -982,13 +996,9 @@ LIGHT_SHADER_CODE #elif defined(DIFFUSE_BURLEY) { - - vec3 H = normalize(V + L); - float cLdotH = max(0.0, dot(L, H)); - - float FD90 = 0.5 + 2.0 * cLdotH * cLdotH * roughness; - float FdV = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotV); - float FdL = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotL); + float FD90_minus_1 = 2.0 * cLdotH * cLdotH * roughness - 0.5; + float FdV = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotV); + float FdL = 1.0 + FD90_minus_1 * SchlickFresnel(cNdotL); diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL; /* float energyBias = mix(roughness, 0.0, 0.5); @@ -1025,13 +1035,9 @@ LIGHT_SHADER_CODE #if defined(SPECULAR_BLINN) //normalized blinn - vec3 H = normalize(V + L); - float cNdotH = max(dot(N, H), 0.0); - float cVdotH = max(dot(V, H), 0.0); - float cLdotH = max(dot(L, H), 0.0); float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; float blinn = pow(cNdotH, shininess); - blinn *= (shininess + 8.0) / (8.0 * 3.141592654); + blinn *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = (blinn) / max(4.0 * cNdotV * cNdotL, 0.75); specular_light += light_color * intensity * specular_blob_intensity * attenuation; @@ -1042,7 +1048,7 @@ LIGHT_SHADER_CODE float cRdotV = max(0.0, dot(R, V)); float shininess = exp2(15.0 * (1.0 - roughness) + 1.0) * 0.25; float phong = pow(cRdotV, shininess); - phong *= (shininess + 8.0) / (8.0 * 3.141592654); + phong *= (shininess + 8.0) * (1.0 / (8.0 * M_PI)); float intensity = (phong) / max(4.0 * cNdotV * cNdotL, 0.75); specular_light += light_color * intensity * specular_blob_intensity * attenuation; @@ -1062,18 +1068,12 @@ LIGHT_SHADER_CODE #elif defined(SPECULAR_SCHLICK_GGX) // shlick+ggx as default - vec3 H = normalize(V + L); - - float cNdotH = max(dot(N, H), 0.0); - float cLdotH = max(dot(L, H), 0.0); - #if defined(LIGHT_USE_ANISOTROPY) + float alpha = roughness * roughness; float aspect = sqrt(1.0 - anisotropy * 0.9); - float rx = roughness / aspect; - float ry = roughness * aspect; - float ax = rx * rx; - float ay = ry * ry; + float ax = alpha / aspect; + float ay = alpha * aspect; float XdotH = dot(T, H); float YdotH = dot(B, H); float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH); @@ -1085,33 +1085,27 @@ LIGHT_SHADER_CODE float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha); #endif // F - //float F0 = 1.0; - //float cLdotH5 = SchlickFresnel(cLdotH); - //float F = mix(cLdotH5, 1.0, F0); + vec3 f0 = F0(metallic, specular, diffuse_color); + float cLdotH5 = SchlickFresnel(cLdotH); + vec3 F = mix(vec3(cLdotH5), vec3(1.0), f0); - float specular_brdf_NL = cNdotL * D /* F */ * G; + vec3 specular_brdf_NL = cNdotL * D * F * G; specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #endif #if defined(LIGHT_USE_CLEARCOAT) - if (clearcoat_gloss > 0.0) { -#if !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN) - vec3 H = normalize(V + L); -#endif + #if !defined(SPECULAR_SCHLICK_GGX) - float cNdotH = max(dot(N, H), 0.0); - float cLdotH = max(dot(L, H), 0.0); - float cLdotH5 = SchlickFresnel(cLdotH); + float cLdotH5 = SchlickFresnel(cLdotH); #endif - float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); - float Fr = mix(.04, 1.0, cLdotH5); - float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); + float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss)); + float Fr = mix(.04, 1.0, cLdotH5); + float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25); - float specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; + float clearcoat_specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL; - specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation; - } + specular_light += clearcoat_specular_brdf_NL * light_color * specular_blob_intensity * attenuation; #endif } @@ -1136,8 +1130,9 @@ float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 p avg += textureProj(shadow, vec4(pos + vec2(0.0, shadow_pixel_size.y * 2.0), depth, 1.0)); avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y * 2.0), depth, 1.0)); return avg * (1.0 / 13.0); +#endif -#elif defined(SHADOW_MODE_PCF_5) +#ifdef SHADOW_MODE_PCF_5 float avg = textureProj(shadow, vec4(pos, depth, 1.0)); avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0)); @@ -1146,7 +1141,9 @@ float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 p avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0)); return avg * (1.0 / 5.0); -#else +#endif + +#if !defined(SHADOW_MODE_PCF_5) || !defined(SHADOW_MODE_PCF_13) return textureProj(shadow, vec4(pos, depth, 1.0)); @@ -1188,7 +1185,7 @@ vec3 light_transmittance(float translucency,vec3 light_vec, vec3 normal, vec3 po } #endif -void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex; float light_length = length(light_rel_vec); @@ -1242,10 +1239,10 @@ void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi light_attenuation *= mix(omni_lights[idx].shadow_color_contact.rgb, vec3(1.0), shadow); } #endif //SHADOWS_DISABLED - light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, omni_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, omni_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, rim * omni_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, omni_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, omni_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * omni_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); } -void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { +void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent, vec3 albedo, vec3 transmission, float roughness, float metallic, float specular, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) { vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex; float light_length = length(light_rel_vec); @@ -1277,7 +1274,7 @@ void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 bi } #endif //SHADOWS_DISABLED - light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, spot_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, spot_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, rim * spot_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, normalize(light_rel_vec), eye_vec, binormal, tangent, spot_lights[idx].light_color_energy.rgb, light_attenuation, albedo, transmission, spot_lights[idx].light_params.z * p_blob_intensity, roughness, metallic, specular, rim * spot_attenuation, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); } void reflection_process(int idx, vec3 vertex, vec3 normal, vec3 binormal, vec3 tangent, float roughness, float anisotropy, vec3 ambient, vec3 skybox, inout highp vec4 reflection_accum, inout highp vec4 ambient_accum) { @@ -1337,7 +1334,7 @@ void reflection_process(int idx, vec3 vertex, vec3 normal, vec3 binormal, vec3 t reflection_accum += reflection; } -#ifndef USE_LIGHTMAP +#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE) if (reflections[idx].ambient.a > 0.0) { //compute ambient using skybox vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal, 0.0)).xyz; @@ -1507,7 +1504,7 @@ void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds, ve //irradiance - vec3 irr_light = voxel_cone_trace(probe, cell_size, probe_pos, environment, blend_ambient, ref_vec, max(min_ref_tan, tan(roughness * 0.5 * M_PI)), max_distance, p_bias); + vec3 irr_light = voxel_cone_trace(probe, cell_size, probe_pos, environment, blend_ambient, ref_vec, max(min_ref_tan, tan(roughness * 0.5 * M_PI * 0.99)), max_distance, p_bias); irr_light *= multiplier; //irr_light=vec3(0.0); @@ -1588,24 +1585,24 @@ void main() { float alpha = 1.0; -#if defined(DO_SIDE_CHECK) - float side = gl_FrontFacing ? 1.0 : -1.0; -#else - float side = 1.0; -#endif - #if defined(ALPHA_SCISSOR_USED) float alpha_scissor = 0.5; #endif #if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY) - vec3 binormal = normalize(binormal_interp) * side; - vec3 tangent = normalize(tangent_interp) * side; + vec3 binormal = normalize(binormal_interp); + vec3 tangent = normalize(tangent_interp); #else vec3 binormal = vec3(0.0); vec3 tangent = vec3(0.0); #endif - vec3 normal = normalize(normal_interp) * side; + vec3 normal = normalize(normal_interp); + +#if defined(DO_SIDE_CHECK) + if (!gl_FrontFacing) { + normal = -normal; + } +#endif #if defined(ENABLE_UV_INTERP) vec2 uv = uv_interp; @@ -1661,7 +1658,7 @@ FRAGMENT_SHADER_CODE normalmap.xy = normalmap.xy * 2.0 - 1.0; normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy))); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc. - normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side; + normal = normalize(mix(normal, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)); #endif @@ -1892,7 +1889,7 @@ FRAGMENT_SHADER_CODE specular_light *= mix(vec3(1.0), light_attenuation, specular_light_interp.a); #else - light_compute(normal, -light_direction_attenuation.xyz, eye_vec, binormal, tangent, light_color_energy.rgb, light_attenuation, albedo, transmission, light_params.z * specular_blob_intensity, roughness, metallic, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); + light_compute(normal, -light_direction_attenuation.xyz, eye_vec, binormal, tangent, light_color_energy.rgb, light_attenuation, albedo, transmission, light_params.z * specular_blob_intensity, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light); #endif #endif //#USE_LIGHT_DIRECTIONAL @@ -1954,7 +1951,7 @@ FRAGMENT_SHADER_CODE } else { specular_light += env_reflection_light; } -#ifndef USE_LIGHTMAP +#if !defined(USE_LIGHTMAP) && !defined(USE_LIGHTMAP_CAPTURE) if (ambient_accum.a > 0.0) { ambient_light = ambient_accum.rgb / ambient_accum.a; } @@ -1966,11 +1963,11 @@ FRAGMENT_SHADER_CODE #else for (int i = 0; i < omni_light_count; i++) { - light_process_omni(omni_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); + light_process_omni(omni_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); } for (int i = 0; i < spot_light_count; i++) { - light_process_spot(spot_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); + light_process_spot(spot_light_indices[i], vertex, eye_vec, normal, binormal, tangent, albedo, transmission, roughness, metallic, specular, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, specular_blob_intensity, diffuse_light, specular_light); } #endif //USE_VERTEX_LIGHTING @@ -1991,7 +1988,7 @@ FRAGMENT_SHADER_CODE diffuse_light *= ao_light_affect; #endif - //energy conservation + // base color remapping diffuse_light *= 1.0 - metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point ambient_light *= 1.0 - metallic; @@ -2008,10 +2005,10 @@ FRAGMENT_SHADER_CODE vec4 r = roughness * c0 + c1; float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0); float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y; - vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw; + vec2 env = vec2(-1.04, 1.04) * a004 + r.zw; - vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo); - specular_light *= AB.x * specular_color + AB.y; + vec3 f0 = F0(metallic, specular, albedo); + specular_light *= env.x * f0 + env.y; #endif } @@ -2030,10 +2027,11 @@ FRAGMENT_SHADER_CODE //apply fog if (fog_depth_enabled) { + float fog_far = fog_depth_end > 0 ? fog_depth_end : z_far; - float fog_z = smoothstep(fog_depth_begin, z_far, length(vertex)); + float fog_z = smoothstep(fog_depth_begin, fog_far, length(vertex)); - fog_amount = pow(fog_z, fog_depth_curve); + fog_amount = pow(fog_z, fog_depth_curve) * fog_density; if (fog_transmit_enabled) { vec3 total_light = emission + ambient_light + specular_light + diffuse_light; float transmit = pow(fog_z, fog_transmit_curve); @@ -2050,7 +2048,7 @@ FRAGMENT_SHADER_CODE emission = emission * rev_amount + fog_color * fog_amount; ambient_light *= rev_amount; - specular_light *rev_amount; + specular_light *= rev_amount; diffuse_light *= rev_amount; } diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl index dd6d78849b..80ad003c80 100644 --- a/drivers/gles3/shaders/tonemap.glsl +++ b/drivers/gles3/shaders/tonemap.glsl @@ -124,13 +124,16 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) { #endif vec3 tonemap_filmic(vec3 color, float white) { - const float A = 0.15f; - const float B = 0.50f; + // exposure bias: input scale (color *= bias, white *= bias) to make the brighness consistent with other tonemappers + // also useful to scale the input to the range that the tonemapper is designed for (some require very high input values) + // has no effect on the curve's general shape or visual properties + const float exposure_bias = 2.0f; + const float A = 0.22f * exposure_bias * exposure_bias; // bias baked into constants for performance + const float B = 0.30f * exposure_bias; const float C = 0.10f; const float D = 0.20f; - const float E = 0.02f; + const float E = 0.01f; const float F = 0.30f; - const float W = 11.2f; vec3 color_tonemapped = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F; float white_tonemapped = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F; @@ -139,10 +142,11 @@ vec3 tonemap_filmic(vec3 color, float white) { } vec3 tonemap_aces(vec3 color, float white) { - const float A = 2.51f; - const float B = 0.03f; - const float C = 2.43f; - const float D = 0.59f; + const float exposure_bias = 0.85f; + const float A = 2.51f * exposure_bias * exposure_bias; + const float B = 0.03f * exposure_bias; + const float C = 2.43f * exposure_bias * exposure_bias; + const float D = 0.59f * exposure_bias; const float E = 0.14f; vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E); @@ -151,8 +155,8 @@ vec3 tonemap_aces(vec3 color, float white) { return clamp(color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f)); } -vec3 tonemap_reindhart(vec3 color, float white) { - return clamp((color) / (1.0f + color) * (1.0f + (color / (white))), vec3(0.0f), vec3(1.0f)); // whitepoint is probably not in linear space here! +vec3 tonemap_reinhard(vec3 color, float white) { + return clamp((white * color + color) / (color * white + white), vec3(0.0f), vec3(1.0f)); } vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped input in range [0;1] @@ -161,8 +165,8 @@ vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped } vec3 apply_tonemapping(vec3 color, float white) { // inputs are LINEAR, always outputs clamped [0;1] color -#ifdef USE_REINDHART_TONEMAPPER - return tonemap_reindhart(color, white); +#ifdef USE_REINHARD_TONEMAPPER + return tonemap_reinhard(color, white); #endif #ifdef USE_FILMIC_TONEMAPPER diff --git a/drivers/png/SCsub b/drivers/png/SCsub index 39480351a6..22fb1817d1 100644 --- a/drivers/png/SCsub +++ b/drivers/png/SCsub @@ -26,14 +26,24 @@ if env['builtin_libpng']: ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - env_png.add_source_files(env.drivers_sources, thirdparty_sources) env_png.Append(CPPPATH=[thirdparty_dir]) + # Needed for drivers includes and in platform/javascript + env.Append(CPPPATH=[thirdparty_dir]) # Currently .ASM filter_neon.S does not compile on NT. import os - if ("neon_enabled" in env and env["neon_enabled"]) and os.name != "nt": + use_neon = "neon_enabled" in env and env["neon_enabled"] and os.name != "nt" + if use_neon: env_png.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=2"]) - env_neon = env_png.Clone() + else: + env_png.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=0"]) + + env_thirdparty = env_png.Clone() + env_thirdparty.disable_warnings() + env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) + + if use_neon: + env_neon = env_thirdparty.Clone() if "S_compiler" in env: env_neon['CC'] = env['S_compiler'] neon_sources = [] @@ -41,8 +51,6 @@ if env['builtin_libpng']: neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon_intrinsics.c")) neon_sources.append(env_neon.Object(thirdparty_dir + "/arm/filter_neon.S")) env.drivers_sources += neon_sources - else: - env_png.Append(CPPFLAGS=["-DPNG_ARM_NEON_OPT=0"]) # Godot source files env_png.add_source_files(env.drivers_sources, "*.cpp") diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp index 04acb9387e..a4ea889d3b 100644 --- a/drivers/png/image_loader_png.cpp +++ b/drivers/png/image_loader_png.cpp @@ -227,10 +227,7 @@ static void user_read_data(png_structp png_ptr, png_bytep data, png_size_t p_len PNGReadStatus *rstatus; rstatus = (PNGReadStatus *)png_get_io_ptr(png_ptr); - png_size_t to_read = p_length; - if (rstatus->size >= 0) { - to_read = MIN(p_length, rstatus->size - rstatus->offset); - } + png_size_t to_read = MIN(p_length, rstatus->size - rstatus->offset); memcpy(data, &rstatus->image[rstatus->offset], to_read); rstatus->offset += to_read; diff --git a/drivers/pulseaudio/SCsub b/drivers/pulseaudio/SCsub index ee39fd2631..28b315ae66 100644 --- a/drivers/pulseaudio/SCsub +++ b/drivers/pulseaudio/SCsub @@ -3,5 +3,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp index 7578fbc0a0..720824d451 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp +++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp @@ -43,10 +43,13 @@ void AudioDriverPulseAudio::pa_state_cb(pa_context *c, void *userdata) { case PA_CONTEXT_FAILED: ad->pa_ready = -1; break; - case PA_CONTEXT_READY: ad->pa_ready = 1; break; + default: + // TODO: Check if we want to handle some of the other + // PA context states like PA_CONTEXT_UNCONNECTED. + break; } } @@ -340,12 +343,12 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { unsigned int out_idx = 0; for (unsigned int i = 0; i < ad->buffer_frames; i++) { - for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) { + for (int j = 0; j < ad->pa_map.channels - 1; j++) { ad->samples_out.write[out_idx++] = ad->samples_in[in_idx++] >> 16; } - uint32_t l = ad->samples_in[in_idx++]; - uint32_t r = ad->samples_in[in_idx++]; - ad->samples_out.write[out_idx++] = ((l >> 1) + (r >> 1)) >> 16; + uint32_t l = ad->samples_in[in_idx++] >> 16; + uint32_t r = ad->samples_in[in_idx++] >> 16; + ad->samples_out.write[out_idx++] = (l + r) / 2; } } } @@ -371,7 +374,7 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { const void *ptr = ad->samples_out.ptr(); ret = pa_stream_write(ad->pa_str, (char *)ptr + write_ofs, bytes_to_write, NULL, 0LL, PA_SEEK_RELATIVE); if (ret != 0) { - ERR_PRINT("pa_stream_write error"); + ERR_PRINTS("PulseAudio: pa_stream_write error: " + String(pa_strerror(ret))); } else { avail_bytes -= bytes_to_write; write_ofs += bytes_to_write; @@ -398,6 +401,9 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) { break; } } + + avail_bytes = 0; + write_ofs = 0; } if (ad->pa_rec_str && pa_stream_get_state(ad->pa_rec_str) == PA_STREAM_READY) { @@ -610,20 +616,18 @@ Error AudioDriverPulseAudio::capture_init_device() { break; } - print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels"); - pa_sample_spec spec; spec.format = PA_SAMPLE_S16LE; spec.channels = pa_rec_map.channels; spec.rate = mix_rate; - int latency = 30; - input_buffer_frames = closest_power_of_2(latency * mix_rate / 1000); - int buffer_size = input_buffer_frames * spec.channels; + int input_latency = 30; + int input_buffer_frames = closest_power_of_2(input_latency * mix_rate / 1000); + int input_buffer_size = input_buffer_frames * spec.channels; pa_buffer_attr attr; - attr.fragsize = buffer_size * sizeof(int16_t); + attr.fragsize = input_buffer_size * sizeof(int16_t); pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map); if (pa_rec_str == NULL) { @@ -639,9 +643,10 @@ Error AudioDriverPulseAudio::capture_init_device() { ERR_FAIL_V(ERR_CANT_OPEN); } - input_buffer.resize(input_buffer_frames * 8); - input_position = 0; - input_size = 0; + input_buffer_init(input_buffer_frames); + + print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels"); + print_verbose("PulseAudio: input buffer frames: " + itos(input_buffer_frames) + " calculated latency: " + itos(input_buffer_frames * 1000 / mix_rate) + "ms"); return OK; } @@ -757,7 +762,6 @@ AudioDriverPulseAudio::AudioDriverPulseAudio() { mix_rate = 0; buffer_frames = 0; - input_buffer_frames = 0; pa_buffer_size = 0; channels = 0; pa_ready = 0; diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.h b/drivers/pulseaudio/audio_driver_pulseaudio.h index f8358a452b..d8bab841ff 100644 --- a/drivers/pulseaudio/audio_driver_pulseaudio.h +++ b/drivers/pulseaudio/audio_driver_pulseaudio.h @@ -64,7 +64,6 @@ class AudioDriverPulseAudio : public AudioDriver { unsigned int mix_rate; unsigned int buffer_frames; - unsigned int input_buffer_frames; unsigned int pa_buffer_size; int channels; int pa_ready; diff --git a/drivers/register_driver_types.cpp b/drivers/register_driver_types.cpp index c6d36a5749..9f5d9c1abf 100644 --- a/drivers/register_driver_types.cpp +++ b/drivers/register_driver_types.cpp @@ -31,11 +31,11 @@ #include "register_driver_types.h" #include "core/math/geometry.h" -#include "png/image_loader_png.h" -#include "png/resource_saver_png.h" +#include "drivers/png/image_loader_png.h" +#include "drivers/png/resource_saver_png.h" #ifdef TOOLS_ENABLED -#include "convex_decomp/b2d_decompose.h" +#include "drivers/convex_decomp/b2d_decompose.h" #endif #ifdef TOOLS_ENABLED diff --git a/drivers/rtaudio/SCsub b/drivers/rtaudio/SCsub index 2b0a602965..285658073c 100644 --- a/drivers/rtaudio/SCsub +++ b/drivers/rtaudio/SCsub @@ -11,9 +11,12 @@ thirdparty_sources = [ ] thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] -env.add_source_files(env.drivers_sources, thirdparty_sources) env.Append(CPPPATH=[thirdparty_dir]) +env_thirdparty = env.Clone() +env_thirdparty.disable_warnings() +env_thirdparty.add_source_files(env.drivers_sources, thirdparty_sources) + # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp index 10ba0663f2..bc6ceb1e7e 100644 --- a/drivers/rtaudio/audio_driver_rtaudio.cpp +++ b/drivers/rtaudio/audio_driver_rtaudio.cpp @@ -114,11 +114,12 @@ Error AudioDriverRtAudio::init() { unsigned int buffer_frames = closest_power_of_2(latency * mix_rate / 1000); print_verbose("Audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms"); - short int tries = 2; + short int tries = 4; - while (tries >= 0) { + while (tries > 0) { switch (speaker_mode) { case SPEAKER_MODE_STEREO: parameters.nChannels = 2; break; + case SPEAKER_SURROUND_31: parameters.nChannels = 4; break; case SPEAKER_SURROUND_51: parameters.nChannels = 6; break; case SPEAKER_SURROUND_71: parameters.nChannels = 8; break; }; @@ -128,12 +129,14 @@ Error AudioDriverRtAudio::init() { active = true; break; - } catch (RtAudioError &e) { + } catch (RtAudioError) { // try with less channels ERR_PRINT("Unable to open audio, retrying with fewer channels..."); switch (speaker_mode) { - case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_MODE_STEREO; break; + case SPEAKER_MODE_STEREO: break; // Required to silence unhandled enum value warning. + case SPEAKER_SURROUND_31: speaker_mode = SPEAKER_MODE_STEREO; break; + case SPEAKER_SURROUND_51: speaker_mode = SPEAKER_SURROUND_31; break; case SPEAKER_SURROUND_71: speaker_mode = SPEAKER_SURROUND_51; break; } diff --git a/drivers/unix/SCsub b/drivers/unix/SCsub index ada8255580..4888f56099 100644 --- a/drivers/unix/SCsub +++ b/drivers/unix/SCsub @@ -5,5 +5,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") env["check_c_headers"] = [ [ "mntent.h", "HAVE_MNTENT" ] ] - -Export('env') diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp index a5a9258c4a..bea249d4b6 100644 --- a/drivers/unix/dir_access_unix.cpp +++ b/drivers/unix/dir_access_unix.cpp @@ -309,7 +309,7 @@ Error DirAccessUnix::change_dir(String p_dir) { // prev_dir is the directory we are changing out of String prev_dir; char real_current_dir_name[2048]; - getcwd(real_current_dir_name, 2048); + ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG); if (prev_dir.parse_utf8(real_current_dir_name)) prev_dir = real_current_dir_name; //no utf8, maybe latin? @@ -328,9 +328,20 @@ Error DirAccessUnix::change_dir(String p_dir) { return ERR_INVALID_PARAMETER; } + String base = _get_root_path(); + if (base != String() && !try_dir.begins_with(base)) { + ERR_FAIL_COND_V(getcwd(real_current_dir_name, 2048) == NULL, ERR_BUG); + String new_dir; + new_dir.parse_utf8(real_current_dir_name); + + if (!new_dir.begins_with(base)) { + try_dir = current_dir; //revert + } + } + // the directory exists, so set current_dir to try_dir current_dir = try_dir; - chdir(prev_dir.utf8().get_data()); + ERR_FAIL_COND_V(chdir(prev_dir.utf8().get_data()) != 0, ERR_BUG); return OK; } @@ -391,7 +402,7 @@ size_t DirAccessUnix::get_space_left() { return vfs.f_bfree * vfs.f_bsize; #else -#warning THIS IS BROKEN + // FIXME: Implement this. return 0; #endif }; @@ -405,7 +416,7 @@ DirAccessUnix::DirAccessUnix() { // set current directory to an absolute path of the current directory char real_current_dir_name[2048]; - getcwd(real_current_dir_name, 2048); + ERR_FAIL_COND(getcwd(real_current_dir_name, 2048) == NULL); if (current_dir.parse_utf8(real_current_dir_name)) current_dir = real_current_dir_name; diff --git a/drivers/unix/net_socket_posix.cpp b/drivers/unix/net_socket_posix.cpp index 6e0bf97711..833b17f122 100644 --- a/drivers/unix/net_socket_posix.cpp +++ b/drivers/unix/net_socket_posix.cpp @@ -42,12 +42,8 @@ #include <sys/types.h> #include <unistd.h> #ifndef NO_FCNTL -#ifdef __HAIKU__ #include <fcntl.h> #else -#include <sys/fcntl.h> -#endif -#else #include <sys/ioctl.h> #endif #include <netinet/in.h> @@ -59,7 +55,7 @@ #include <netinet/tcp.h> -#if defined(OSX_ENABLED) || defined(IPHONE_ENABLED) +#if defined(__APPLE__) #define MSG_NOSIGNAL SO_NOSIGPIPE #endif @@ -94,7 +90,7 @@ #endif -static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) { +size_t NetSocketPosix::_set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type) { memset(p_addr, 0, sizeof(struct sockaddr_storage)); if (p_ip_type == IP::TYPE_IPV6 || p_ip_type == IP::TYPE_ANY) { // IPv6 socket @@ -114,7 +110,7 @@ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Addres } else { // IPv4 socket // IPv4 socket with IPv6 address - ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0); + ERR_FAIL_COND_V(!p_ip.is_wildcard() && !p_ip.is_ipv4(), 0); struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; addr4->sin_family = AF_INET; @@ -126,12 +122,11 @@ static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Addres addr4->sin_addr.s_addr = INADDR_ANY; } - copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); return sizeof(sockaddr_in); } } -static void _set_ip_port(IP_Address &r_ip, uint16_t &r_port, struct sockaddr_storage *p_addr) { +void NetSocketPosix::_set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port) { if (p_addr->ss_family == AF_INET) { @@ -559,7 +554,7 @@ void NetSocketPosix::set_ipv6_only_enabled(bool p_enabled) { void NetSocketPosix::set_tcp_no_delay_enabled(bool p_enabled) { ERR_FAIL_COND(!is_open()); - ERR_FAIL_COND(_ip_type != TYPE_TCP); + ERR_FAIL_COND(!_is_stream); // Not TCP int par = p_enabled ? 1 : 0; if (setsockopt(_sock, IPPROTO_TCP, TCP_NODELAY, SOCK_CBUF(&par), sizeof(int)) < 0) { @@ -612,7 +607,7 @@ Ref<NetSocket> NetSocketPosix::accept(IP_Address &r_ip, uint16_t &r_port) { SOCKET_TYPE fd = ::accept(_sock, (struct sockaddr *)&their_addr, &size); ERR_FAIL_COND_V(fd == SOCK_EMPTY, out); - _set_ip_port(r_ip, r_port, &their_addr); + _set_ip_port(&their_addr, r_ip, r_port); NetSocketPosix *ns = memnew(NetSocketPosix); ns->_set_socket(fd, _ip_type, _is_stream); diff --git a/drivers/unix/net_socket_posix.h b/drivers/unix/net_socket_posix.h index 8177e01987..010f2ea6e0 100644 --- a/drivers/unix/net_socket_posix.h +++ b/drivers/unix/net_socket_posix.h @@ -39,6 +39,7 @@ #define SOCKET_TYPE SOCKET #else +#include <sys/socket.h> #define SOCKET_TYPE int #endif @@ -68,6 +69,8 @@ protected: public: static void make_default(); static void cleanup(); + static void _set_ip_port(struct sockaddr_storage *p_addr, IP_Address &r_ip, uint16_t &r_port); + static size_t _set_addr_storage(struct sockaddr_storage *p_addr, const IP_Address &p_ip, uint16_t p_port, IP::Type p_ip_type); virtual Error open(Type p_sock_type, IP::Type &ip_type); virtual void close(); diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp index 9936c95cf9..279274734f 100644 --- a/drivers/unix/os_unix.cpp +++ b/drivers/unix/os_unix.cpp @@ -45,6 +45,7 @@ #ifdef __APPLE__ #include <mach-o/dyld.h> +#include <mach/mach_time.h> #endif #if defined(__FreeBSD__) || defined(__OpenBSD__) @@ -64,6 +65,32 @@ #include <sys/wait.h> #include <unistd.h> +/// Clock Setup function (used by get_ticks_usec) +static uint64_t _clock_start = 0; +#if defined(__APPLE__) +static double _clock_scale = 0; +static void _setup_clock() { + mach_timebase_info_data_t info; + kern_return_t ret = mach_timebase_info(&info); + ERR_EXPLAIN("OS CLOCK IS NOT WORKING!"); + ERR_FAIL_COND(ret != 0); + _clock_scale = ((double)info.numer / (double)info.denom) / 1000.0; + _clock_start = mach_absolute_time() * _clock_scale; +} +#else +#if defined(CLOCK_MONOTONIC_RAW) && !defined(JAVASCRIPT_ENABLED) // This is a better clock on Linux. +#define GODOT_CLOCK CLOCK_MONOTONIC_RAW +#else +#define GODOT_CLOCK CLOCK_MONOTONIC +#endif +static void _setup_clock() { + struct timespec tv_now = { 0, 0 }; + ERR_EXPLAIN("OS CLOCK IS NOT WORKING!"); + ERR_FAIL_COND(clock_gettime(GODOT_CLOCK, &tv_now) != 0); + _clock_start = ((uint64_t)tv_now.tv_nsec / 1000L) + (uint64_t)tv_now.tv_sec * 1000000L; +} +#endif + void OS_Unix::debug_break() { assert(false); @@ -126,8 +153,7 @@ void OS_Unix::initialize_core() { IP_Unix::make_default(); #endif - ticks_start = 0; - ticks_start = get_ticks_usec(); + _setup_clock(); struct sigaction sa; sa.sa_handler = &handle_sigchld; @@ -246,17 +272,27 @@ void OS_Unix::delay_usec(uint32_t p_usec) const { } uint64_t OS_Unix::get_ticks_usec() const { - struct timeval tv_now; - gettimeofday(&tv_now, NULL); - - uint64_t longtime = (uint64_t)tv_now.tv_usec + (uint64_t)tv_now.tv_sec * 1000000L; - longtime -= ticks_start; +#if defined(__APPLE__) + uint64_t longtime = mach_absolute_time() * _clock_scale; +#else + // Unchecked return. Static analyzers might complain. + // If _setup_clock() succeded, we assume clock_gettime() works. + struct timespec tv_now = { 0, 0 }; + clock_gettime(GODOT_CLOCK, &tv_now); + uint64_t longtime = ((uint64_t)tv_now.tv_nsec / 1000L) + (uint64_t)tv_now.tv_sec * 1000000L; +#endif + longtime -= _clock_start; return longtime; } Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bool p_blocking, ProcessID *r_child_id, String *r_pipe, int *r_exitcode, bool read_stderr) { +#ifdef __EMSCRIPTEN__ + // Don't compile this code at all to avoid undefined references. + // Actual virtual call goes to OS_JavaScript. + ERR_FAIL_V(ERR_BUG); +#else if (p_blocking && r_pipe) { String argss; @@ -323,6 +359,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, bo } return OK; +#endif } Error OS_Unix::kill(const ProcessID &p_pid) { @@ -456,9 +493,11 @@ String OS_Unix::get_executable_path() const { //fix for running from a symlink char buf[256]; memset(buf, 0, 256); - readlink("/proc/self/exe", buf, sizeof(buf)); + ssize_t len = readlink("/proc/self/exe", buf, sizeof(buf)); String b; - b.parse_utf8(buf); + if (len > 0) { + b.parse_utf8(buf, len); + } if (b == "") { WARN_PRINT("Couldn't get executable path from /proc/self/exe, using argv[0]"); return OS::get_executable_path(); diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h index f4abfa2dd4..b702454603 100644 --- a/drivers/unix/os_unix.h +++ b/drivers/unix/os_unix.h @@ -42,8 +42,6 @@ class OS_Unix : public OS { - uint64_t ticks_start; - protected: // UNIX only handles the core functions. // inheriting platforms under unix (eg. X11) should handle the rest diff --git a/drivers/unix/socket_helpers.h b/drivers/unix/socket_helpers.h deleted file mode 100644 index 5b42c13eae..0000000000 --- a/drivers/unix/socket_helpers.h +++ /dev/null @@ -1,156 +0,0 @@ -/*************************************************************************/ -/* socket_helpers.h */ -/*************************************************************************/ -/* This file is part of: */ -/* GODOT ENGINE */ -/* https://godotengine.org */ -/*************************************************************************/ -/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */ -/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */ -/* */ -/* Permission is hereby granted, free of charge, to any person obtaining */ -/* a copy of this software and associated documentation files (the */ -/* "Software"), to deal in the Software without restriction, including */ -/* without limitation the rights to use, copy, modify, merge, publish, */ -/* distribute, sublicense, and/or sell copies of the Software, and to */ -/* permit persons to whom the Software is furnished to do so, subject to */ -/* the following conditions: */ -/* */ -/* The above copyright notice and this permission notice shall be */ -/* included in all copies or substantial portions of the Software. */ -/* */ -/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ -/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ -/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/ -/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ -/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ -/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ -/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -/*************************************************************************/ - -#ifndef SOCKET_HELPERS_H -#define SOCKET_HELPERS_H - -#include <string.h> - -#if defined(__MINGW32__) && (!defined(__MINGW64_VERSION_MAJOR) || __MINGW64_VERSION_MAJOR < 4) -// Workaround for mingw-w64 < 4.0 -#ifndef IPV6_V6ONLY -#define IPV6_V6ONLY 27 -#endif -#endif - -// helpers for sockaddr -> IP_Address and back, should work for posix and winsock. All implementations should use this - -static size_t _set_sockaddr(struct sockaddr_storage *p_addr, const IP_Address &p_ip, int p_port, IP::Type p_sock_type = IP::TYPE_ANY) { - - memset(p_addr, 0, sizeof(struct sockaddr_storage)); - - ERR_FAIL_COND_V(!p_ip.is_valid(), 0); - - // IPv6 socket - if (p_sock_type == IP::TYPE_IPV6 || p_sock_type == IP::TYPE_ANY) { - - // IPv6 only socket with IPv4 address - ERR_FAIL_COND_V(p_sock_type == IP::TYPE_IPV6 && p_ip.is_ipv4(), 0); - - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - addr6->sin6_family = AF_INET6; - addr6->sin6_port = htons(p_port); - copymem(&addr6->sin6_addr.s6_addr, p_ip.get_ipv6(), 16); - return sizeof(sockaddr_in6); - - } else { // IPv4 socket - - // IPv4 socket with IPv6 address - ERR_FAIL_COND_V(!p_ip.is_ipv4(), 0); - - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - addr4->sin_family = AF_INET; - addr4->sin_port = htons(p_port); // short, network byte order - copymem(&addr4->sin_addr.s_addr, p_ip.get_ipv4(), 16); - return sizeof(sockaddr_in); - }; -}; - -static size_t _set_listen_sockaddr(struct sockaddr_storage *p_addr, int p_port, IP::Type p_sock_type, const IP_Address p_bind_address) { - - memset(p_addr, 0, sizeof(struct sockaddr_storage)); - if (p_sock_type == IP::TYPE_IPV4) { - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - addr4->sin_family = AF_INET; - addr4->sin_port = htons(p_port); - if (p_bind_address.is_valid()) { - copymem(&addr4->sin_addr.s_addr, p_bind_address.get_ipv4(), 4); - } else { - addr4->sin_addr.s_addr = INADDR_ANY; - } - return sizeof(sockaddr_in); - } else { - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - - addr6->sin6_family = AF_INET6; - addr6->sin6_port = htons(p_port); - if (p_bind_address.is_valid()) { - copymem(&addr6->sin6_addr.s6_addr, p_bind_address.get_ipv6(), 16); - } else { - addr6->sin6_addr = in6addr_any; - } - return sizeof(sockaddr_in6); - }; -}; - -static int _socket_create(IP::Type &p_type, int type, int protocol) { - - ERR_FAIL_COND_V(p_type > IP::TYPE_ANY || p_type < IP::TYPE_NONE, ERR_INVALID_PARAMETER); - - int family = p_type == IP::TYPE_IPV4 ? AF_INET : AF_INET6; - int sockfd = socket(family, type, protocol); - - if (sockfd == -1 && p_type == IP::TYPE_ANY) { - // Careful here, changing the referenced parameter so the caller knows that we are using an IPv4 socket - // in place of a dual stack one, and further calls to _set_sock_addr will work as expected. - p_type = IP::TYPE_IPV4; - family = AF_INET; - sockfd = socket(family, type, protocol); - } - - ERR_FAIL_COND_V(sockfd == -1, -1); - - if (family == AF_INET6) { - // Select IPv4 over IPv6 mapping - int opt = p_type != IP::TYPE_ANY; - if (setsockopt(sockfd, IPPROTO_IPV6, IPV6_V6ONLY, (const char *)&opt, sizeof(opt)) != 0) { - WARN_PRINT("Unable to set/unset IPv4 address mapping over IPv6"); - } - } - if (protocol == IPPROTO_UDP && p_type != IP::TYPE_IPV6) { - // Enable broadcasting for UDP sockets if it's not IPv6 only (IPv6 has no broadcast option). - int broadcast = 1; - if (setsockopt(sockfd, SOL_SOCKET, SO_BROADCAST, (char *)&broadcast, sizeof(broadcast)) != 0) { - WARN_PRINT("Error when enabling broadcasting"); - } - } - - return sockfd; -} - -static void _set_ip_addr_port(IP_Address &r_ip, int &r_port, struct sockaddr_storage *p_addr) { - - if (p_addr->ss_family == AF_INET) { - - struct sockaddr_in *addr4 = (struct sockaddr_in *)p_addr; - r_ip.set_ipv4((uint8_t *)&(addr4->sin_addr.s_addr)); - - r_port = ntohs(addr4->sin_port); - - } else if (p_addr->ss_family == AF_INET6) { - - struct sockaddr_in6 *addr6 = (struct sockaddr_in6 *)p_addr; - r_ip.set_ipv6(addr6->sin6_addr.s6_addr); - - r_port = ntohs(addr6->sin6_port); - }; -}; - -#endif diff --git a/drivers/unix/thread_posix.cpp b/drivers/unix/thread_posix.cpp index fcefe0a3b3..54bbbf2dad 100644 --- a/drivers/unix/thread_posix.cpp +++ b/drivers/unix/thread_posix.cpp @@ -103,8 +103,6 @@ void ThreadPosix::wait_to_finish_func_posix(Thread *p_thread) { Error ThreadPosix::set_name_func_posix(const String &p_name) { - pthread_t running_thread = pthread_self(); - #ifdef PTHREAD_NO_RENAME return ERR_UNAVAILABLE; @@ -117,6 +115,7 @@ Error ThreadPosix::set_name_func_posix(const String &p_name) { #else + pthread_t running_thread = pthread_self(); #ifdef PTHREAD_BSD_SET_NAME pthread_set_name_np(running_thread, p_name.utf8().get_data()); int err = 0; // Open/FreeBSD ignore errors in this function diff --git a/drivers/wasapi/SCsub b/drivers/wasapi/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/wasapi/SCsub +++ b/drivers/wasapi/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp index 3d4979175b..8665f701b1 100644 --- a/drivers/wasapi/audio_driver_wasapi.cpp +++ b/drivers/wasapi/audio_driver_wasapi.cpp @@ -336,10 +336,7 @@ Error AudioDriverWASAPI::init_capture_device(bool reinit) { HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames); ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN); - // Set the buffer size - input_buffer.resize(max_frames * CAPTURE_BUFFER_CHANNELS); - input_position = 0; - input_size = 0; + input_buffer_init(max_frames); return OK; } @@ -796,19 +793,18 @@ Error AudioDriverWASAPI::capture_start() { return err; } - if (audio_input.active == false) { - audio_input.audio_client->Start(); - audio_input.active = true; - - return OK; + if (audio_input.active) { + return FAILED; } - return FAILED; + audio_input.audio_client->Start(); + audio_input.active = true; + return OK; } Error AudioDriverWASAPI::capture_stop() { - if (audio_input.active == true) { + if (audio_input.active) { audio_input.audio_client->Stop(); audio_input.active = false; diff --git a/drivers/windows/SCsub b/drivers/windows/SCsub index ee39fd2631..28b315ae66 100644 --- a/drivers/windows/SCsub +++ b/drivers/windows/SCsub @@ -3,5 +3,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp index b4492a2022..2582478259 100644 --- a/drivers/windows/file_access_windows.cpp +++ b/drivers/windows/file_access_windows.cpp @@ -114,7 +114,7 @@ Error FileAccessWindows::_open(const String &p_path, int p_mode_flags) { path = path + ".tmp"; } - f = _wfopen(path.c_str(), mode_string); + _wfopen_s(&f, path.c_str(), mode_string); if (f == NULL) { last_error = ERR_FILE_CANT_OPEN; @@ -278,7 +278,7 @@ bool FileAccessWindows::file_exists(const String &p_name) { FILE *g; //printf("opening file %s\n", p_fname.c_str()); String filename = fix_path(p_name); - g = _wfopen(filename.c_str(), L"rb"); + _wfopen_s(&g, filename.c_str(), L"rb"); if (g == NULL) { return false; diff --git a/drivers/winmidi/SCsub b/drivers/winmidi/SCsub index 233593b0f9..4c24925192 100644 --- a/drivers/winmidi/SCsub +++ b/drivers/winmidi/SCsub @@ -4,5 +4,3 @@ Import('env') # Driver source files env.add_source_files(env.drivers_sources, "*.cpp") - -Export('env') diff --git a/drivers/xaudio2/SCsub b/drivers/xaudio2/SCsub index cb780a893b..3dca95b429 100644 --- a/drivers/xaudio2/SCsub +++ b/drivers/xaudio2/SCsub @@ -5,5 +5,3 @@ Import('env') env.add_source_files(env.drivers_sources, "*.cpp") env.Append(CXXFLAGS=['-DXAUDIO2_ENABLED']) env.Append(LINKFLAGS=['xaudio2_8.lib']) - -Export('env') diff --git a/drivers/zlib/SCsub b/drivers/zlib/SCsub deleted file mode 100644 index 407deb5f6e..0000000000 --- a/drivers/zlib/SCsub +++ /dev/null @@ -1,26 +0,0 @@ -#!/usr/bin/env python - -Import('env') - -# Not cloning the env, the includes need to be accessible for core/ - -# Thirdparty source files -# No check here as already done in drivers/SCsub -thirdparty_dir = "#thirdparty/zlib/" -thirdparty_sources = [ - "adler32.c", - "compress.c", - "crc32.c", - "deflate.c", - "infback.c", - "inffast.c", - "inflate.c", - "inftrees.c", - "trees.c", - "uncompr.c", - "zutil.c", -] -thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources] - -env.add_source_files(env.drivers_sources, thirdparty_sources) -env.Append(CPPPATH=[thirdparty_dir]) |