summaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
Diffstat (limited to 'drivers')
-rw-r--r--drivers/SCsub5
-rw-r--r--drivers/alsa/audio_driver_alsa.cpp98
-rw-r--r--drivers/alsa/audio_driver_alsa.h1
-rw-r--r--drivers/alsamidi/SCsub8
-rw-r--r--drivers/alsamidi/alsa_midi.cpp201
-rw-r--r--drivers/alsamidi/alsa_midi.h69
-rw-r--r--drivers/convex_decomp/b2d_decompose.h2
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp356
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.h37
-rw-r--r--drivers/coremidi/SCsub8
-rw-r--r--drivers/coremidi/core_midi.cpp124
-rw-r--r--drivers/coremidi/core_midi.h63
-rw-r--r--drivers/dummy/rasterizer_dummy.h31
-rw-r--r--drivers/dummy/texture_loader_dummy.cpp4
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.cpp218
-rw-r--r--drivers/gles2/rasterizer_canvas_gles2.h2
-rw-r--r--drivers/gles2/rasterizer_gles2.cpp110
-rw-r--r--drivers/gles2/rasterizer_gles2.h6
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.cpp2267
-rw-r--r--drivers/gles2/rasterizer_scene_gles2.h333
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.cpp2387
-rw-r--r--drivers/gles2/rasterizer_storage_gles2.h388
-rw-r--r--drivers/gles2/shader_compiler_gles2.cpp88
-rw-r--r--drivers/gles2/shader_gles2.cpp429
-rw-r--r--drivers/gles2/shader_gles2.h216
-rw-r--r--drivers/gles2/shaders/SCsub4
-rw-r--r--drivers/gles2/shaders/blend_shape.glsl43
-rw-r--r--drivers/gles2/shaders/canvas.glsl43
-rw-r--r--drivers/gles2/shaders/canvas_shadow.glsl23
-rw-r--r--drivers/gles2/shaders/copy.glsl70
-rw-r--r--drivers/gles2/shaders/cube_to_dp.glsl86
-rw-r--r--drivers/gles2/shaders/cubemap_filter.glsl338
-rw-r--r--drivers/gles2/shaders/effect_blur.glsl182
-rw-r--r--drivers/gles2/shaders/exposure.glsl64
-rw-r--r--drivers/gles2/shaders/particles.glsl122
-rw-r--r--drivers/gles2/shaders/resolve.glsl20
-rw-r--r--drivers/gles2/shaders/scene.glsl2313
-rw-r--r--drivers/gles2/shaders/screen_space_reflection.glsl199
-rw-r--r--drivers/gles2/shaders/ssao.glsl164
-rw-r--r--drivers/gles2/shaders/ssao_blur.glsl55
-rw-r--r--drivers/gles2/shaders/ssao_minify.glsl21
-rw-r--r--drivers/gles2/shaders/stdlib.glsl37
-rw-r--r--drivers/gles2/shaders/subsurf_scattering.glsl168
-rw-r--r--drivers/gles2/shaders/tonemap.glsl168
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp175
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp76
-rw-r--r--drivers/gles3/rasterizer_gles3.h6
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp152
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.h7
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.cpp505
-rw-r--r--drivers/gles3/rasterizer_storage_gles3.h40
-rw-r--r--drivers/gles3/shader_compiler_gles3.cpp29
-rw-r--r--drivers/gles3/shader_compiler_gles3.h1
-rw-r--r--drivers/gles3/shader_gles3.cpp11
-rw-r--r--drivers/gles3/shaders/blend_shape.glsl43
-rw-r--r--drivers/gles3/shaders/canvas.glsl454
-rw-r--r--drivers/gles3/shaders/canvas_shadow.glsl28
-rw-r--r--drivers/gles3/shaders/copy.glsl96
-rw-r--r--drivers/gles3/shaders/cube_to_dp.glsl72
-rw-r--r--drivers/gles3/shaders/cubemap_filter.glsl253
-rw-r--r--drivers/gles3/shaders/effect_blur.glsl182
-rw-r--r--drivers/gles3/shaders/exposure.glsl64
-rw-r--r--drivers/gles3/shaders/particles.glsl125
-rw-r--r--drivers/gles3/shaders/resolve.glsl24
-rw-r--r--drivers/gles3/shaders/scene.glsl1396
-rw-r--r--drivers/gles3/shaders/screen_space_reflection.glsl244
-rw-r--r--drivers/gles3/shaders/ssao.glsl176
-rw-r--r--drivers/gles3/shaders/ssao_blur.glsl61
-rw-r--r--drivers/gles3/shaders/ssao_minify.glsl21
-rw-r--r--drivers/gles3/shaders/subsurf_scattering.glsl168
-rw-r--r--drivers/gles3/shaders/tonemap.glsl310
-rw-r--r--drivers/png/image_loader_png.cpp1
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp359
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.h24
-rw-r--r--drivers/rtaudio/audio_driver_rtaudio.cpp9
-rw-r--r--drivers/unix/file_access_unix.cpp7
-rw-r--r--drivers/wasapi/audio_driver_wasapi.cpp565
-rw-r--r--drivers/wasapi/audio_driver_wasapi.h65
-rw-r--r--drivers/windows/file_access_windows.cpp26
-rw-r--r--drivers/winmidi/SCsub8
-rw-r--r--drivers/winmidi/win_midi.cpp106
-rw-r--r--drivers/winmidi/win_midi.h61
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.cpp4
-rw-r--r--drivers/xaudio2/audio_driver_xaudio2.h2
84 files changed, 11739 insertions, 5788 deletions
diff --git a/drivers/SCsub b/drivers/SCsub
index 2c5e9434e8..f9cfa3fb05 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -21,6 +21,11 @@ if (env["platform"] == "windows"):
if env['xaudio2']:
SConscript("xaudio2/SCsub")
+# Midi drivers
+SConscript('alsamidi/SCsub')
+SConscript('coremidi/SCsub')
+SConscript('winmidi/SCsub')
+
# Graphics drivers
if (env["platform"] != "server"):
SConscript('gles3/SCsub')
diff --git a/drivers/alsa/audio_driver_alsa.cpp b/drivers/alsa/audio_driver_alsa.cpp
index 1e17e72532..1f53d52951 100644
--- a/drivers/alsa/audio_driver_alsa.cpp
+++ b/drivers/alsa/audio_driver_alsa.cpp
@@ -58,7 +58,10 @@ Error AudioDriverALSA::init_device() {
#define CHECK_FAIL(m_cond) \
if (m_cond) { \
fprintf(stderr, "ALSA ERR: %s\n", snd_strerror(status)); \
- snd_pcm_close(pcm_handle); \
+ if (pcm_handle) { \
+ snd_pcm_close(pcm_handle); \
+ pcm_handle = NULL; \
+ } \
ERR_FAIL_COND_V(m_cond, ERR_CANT_OPEN); \
}
@@ -113,9 +116,7 @@ Error AudioDriverALSA::init_device() {
status = snd_pcm_hw_params_set_period_size_near(pcm_handle, hwparams, &period_size, NULL);
CHECK_FAIL(status < 0);
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("audio buffer frames: " + itos(period_size) + " calculated latency: " + itos(period_size * 1000 / mix_rate) + "ms");
- }
+ print_verbose("Audio buffer frames: " + itos(period_size) + " calculated latency: " + itos(period_size * 1000 / mix_rate) + "ms");
status = snd_pcm_hw_params_set_periods_near(pcm_handle, hwparams, &periods, NULL);
CHECK_FAIL(status < 0);
@@ -142,8 +143,6 @@ Error AudioDriverALSA::init_device() {
samples_in.resize(period_size * channels);
samples_out.resize(period_size * channels);
- snd_pcm_nonblock(pcm_handle, 0);
-
return OK;
}
@@ -152,7 +151,6 @@ Error AudioDriverALSA::init() {
active = false;
thread_exited = false;
exit_thread = false;
- pcm_open = false;
Error err = init_device();
if (err == OK) {
@@ -168,54 +166,50 @@ void AudioDriverALSA::thread_func(void *p_udata) {
AudioDriverALSA *ad = (AudioDriverALSA *)p_udata;
while (!ad->exit_thread) {
+
+ ad->lock();
+ ad->start_counting_ticks();
+
if (!ad->active) {
for (unsigned int i = 0; i < ad->period_size * ad->channels; i++) {
- ad->samples_out[i] = 0;
- };
- } else {
- ad->lock();
+ ad->samples_out.write[i] = 0;
+ }
+ } else {
ad->audio_server_process(ad->period_size, ad->samples_in.ptrw());
- ad->unlock();
-
for (unsigned int i = 0; i < ad->period_size * ad->channels; i++) {
- ad->samples_out[i] = ad->samples_in[i] >> 16;
+ ad->samples_out.write[i] = ad->samples_in[i] >> 16;
}
- };
+ }
int todo = ad->period_size;
int total = 0;
- while (todo) {
- if (ad->exit_thread)
- break;
+ while (todo && !ad->exit_thread) {
uint8_t *src = (uint8_t *)ad->samples_out.ptr();
int wrote = snd_pcm_writei(ad->pcm_handle, (void *)(src + (total * ad->channels)), todo);
- if (wrote < 0) {
- if (ad->exit_thread)
- break;
+ if (wrote > 0) {
+ total += wrote;
+ todo -= wrote;
+ } else if (wrote == -EAGAIN) {
+ ad->stop_counting_ticks();
+ ad->unlock();
- if (wrote == -EAGAIN) {
- //can't write yet (though this is blocking..)
- usleep(1000);
- continue;
- }
+ OS::get_singleton()->delay_usec(1000);
+
+ ad->lock();
+ ad->start_counting_ticks();
+ } else {
wrote = snd_pcm_recover(ad->pcm_handle, wrote, 0);
if (wrote < 0) {
- //absolute fail
- fprintf(stderr, "ALSA failed and can't recover: %s\n", snd_strerror(wrote));
+ ERR_PRINTS("ALSA: Failed and can't recover: " + String(snd_strerror(wrote)));
ad->active = false;
ad->exit_thread = true;
- break;
}
- continue;
- };
-
- total += wrote;
- todo -= wrote;
- };
+ }
+ }
// User selected a new device, finish the current one so we'll init the new device
if (ad->device_name != ad->new_device) {
@@ -232,10 +226,12 @@ void AudioDriverALSA::thread_func(void *p_udata) {
if (err != OK) {
ad->active = false;
ad->exit_thread = true;
- break;
}
}
}
+
+ ad->stop_counting_ticks();
+ ad->unlock();
};
ad->thread_exited = true;
@@ -296,7 +292,9 @@ String AudioDriverALSA::get_device() {
void AudioDriverALSA::set_device(String device) {
+ lock();
new_device = device;
+ unlock();
}
void AudioDriverALSA::lock() {
@@ -315,29 +313,29 @@ void AudioDriverALSA::unlock() {
void AudioDriverALSA::finish_device() {
- if (pcm_open) {
+ if (pcm_handle) {
snd_pcm_close(pcm_handle);
- pcm_open = NULL;
+ pcm_handle = NULL;
}
}
void AudioDriverALSA::finish() {
- if (!thread)
- return;
-
- exit_thread = true;
- Thread::wait_to_finish(thread);
+ if (thread) {
+ exit_thread = true;
+ Thread::wait_to_finish(thread);
- finish_device();
+ memdelete(thread);
+ thread = NULL;
- memdelete(thread);
- if (mutex) {
- memdelete(mutex);
- mutex = NULL;
+ if (mutex) {
+ memdelete(mutex);
+ mutex = NULL;
+ }
}
- thread = NULL;
-};
+
+ finish_device();
+}
AudioDriverALSA::AudioDriverALSA() {
diff --git a/drivers/alsa/audio_driver_alsa.h b/drivers/alsa/audio_driver_alsa.h
index 2878e100a2..e2a2325cf3 100644
--- a/drivers/alsa/audio_driver_alsa.h
+++ b/drivers/alsa/audio_driver_alsa.h
@@ -66,7 +66,6 @@ class AudioDriverALSA : public AudioDriver {
bool active;
bool thread_exited;
mutable bool exit_thread;
- bool pcm_open;
public:
const char *get_name() const {
diff --git a/drivers/alsamidi/SCsub b/drivers/alsamidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/alsamidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/alsamidi/alsa_midi.cpp b/drivers/alsamidi/alsa_midi.cpp
new file mode 100644
index 0000000000..599470d7e0
--- /dev/null
+++ b/drivers/alsamidi/alsa_midi.cpp
@@ -0,0 +1,201 @@
+/*************************************************************************/
+/* alsa_midi.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef ALSAMIDI_ENABLED
+
+#include <errno.h>
+
+#include "alsa_midi.h"
+#include "os/os.h"
+#include "print_string.h"
+
+static int get_message_size(uint8_t message) {
+ switch (message & 0xF0) {
+ case 0x80: // note off
+ case 0x90: // note on
+ case 0xA0: // aftertouch
+ case 0xB0: // continuous controller
+ return 3;
+
+ case 0xC0: // patch change
+ case 0xD0: // channel pressure
+ case 0xE0: // pitch bend
+ return 2;
+ }
+
+ return 256;
+}
+
+void MIDIDriverALSAMidi::thread_func(void *p_udata) {
+ MIDIDriverALSAMidi *md = (MIDIDriverALSAMidi *)p_udata;
+ uint64_t timestamp = 0;
+ uint8_t buffer[256];
+ int expected_size = 255;
+ int bytes = 0;
+
+ while (!md->exit_thread) {
+ int ret;
+
+ md->lock();
+
+ for (int i = 0; i < md->connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = md->connected_inputs[i];
+ do {
+ uint8_t byte = 0;
+ ret = snd_rawmidi_read(midi_in, &byte, 1);
+ if (ret < 0) {
+ if (ret != -EAGAIN) {
+ ERR_PRINTS("snd_rawmidi_read error: " + String(snd_strerror(ret)));
+ }
+ } else {
+ if (byte & 0x80) {
+ // Flush previous packet if there is any
+ if (bytes) {
+ md->receive_input_packet(timestamp, buffer, bytes);
+ bytes = 0;
+ }
+ expected_size = get_message_size(byte);
+ }
+
+ if (bytes < 256) {
+ buffer[bytes++] = byte;
+ // If we know the size of the current packet receive it if it reached the expected size
+ if (bytes >= expected_size) {
+ md->receive_input_packet(timestamp, buffer, bytes);
+ bytes = 0;
+ }
+ }
+ }
+ } while (ret > 0);
+ }
+
+ md->unlock();
+
+ OS::get_singleton()->delay_usec(1000);
+ }
+}
+
+Error MIDIDriverALSAMidi::open() {
+
+ void **hints;
+
+ if (snd_device_name_hint(-1, "rawmidi", &hints) < 0)
+ return ERR_CANT_OPEN;
+
+ int i = 0;
+ for (void **n = hints; *n != NULL; n++) {
+ char *name = snd_device_name_get_hint(*n, "NAME");
+
+ if (name != NULL) {
+ snd_rawmidi_t *midi_in;
+ int ret = snd_rawmidi_open(&midi_in, NULL, name, SND_RAWMIDI_NONBLOCK);
+ if (ret >= 0) {
+ connected_inputs.insert(i++, midi_in);
+ }
+ }
+
+ if (name != NULL)
+ free(name);
+ }
+ snd_device_name_free_hint(hints);
+
+ mutex = Mutex::create();
+ thread = Thread::create(MIDIDriverALSAMidi::thread_func, this);
+
+ return OK;
+}
+
+void MIDIDriverALSAMidi::close() {
+
+ if (thread) {
+ exit_thread = true;
+ Thread::wait_to_finish(thread);
+
+ memdelete(thread);
+ thread = NULL;
+ }
+
+ if (mutex) {
+ memdelete(mutex);
+ mutex = NULL;
+ }
+
+ for (int i = 0; i < connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_close(midi_in);
+ }
+ connected_inputs.clear();
+}
+
+void MIDIDriverALSAMidi::lock() const {
+
+ if (mutex)
+ mutex->lock();
+}
+
+void MIDIDriverALSAMidi::unlock() const {
+
+ if (mutex)
+ mutex->unlock();
+}
+
+PoolStringArray MIDIDriverALSAMidi::get_connected_inputs() {
+
+ PoolStringArray list;
+
+ lock();
+ for (int i = 0; i < connected_inputs.size(); i++) {
+ snd_rawmidi_t *midi_in = connected_inputs[i];
+ snd_rawmidi_info_t *info;
+
+ snd_rawmidi_info_malloc(&info);
+ snd_rawmidi_info(midi_in, info);
+ list.push_back(snd_rawmidi_info_get_name(info));
+ snd_rawmidi_info_free(info);
+ }
+ unlock();
+
+ return list;
+}
+
+MIDIDriverALSAMidi::MIDIDriverALSAMidi() {
+
+ mutex = NULL;
+ thread = NULL;
+
+ exit_thread = false;
+}
+
+MIDIDriverALSAMidi::~MIDIDriverALSAMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/alsamidi/alsa_midi.h b/drivers/alsamidi/alsa_midi.h
new file mode 100644
index 0000000000..90e458a365
--- /dev/null
+++ b/drivers/alsamidi/alsa_midi.h
@@ -0,0 +1,69 @@
+/*************************************************************************/
+/* alsa_midi.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef ALSAMIDI_ENABLED
+
+#ifndef ALSA_MIDI_H
+#define ALSA_MIDI_H
+
+#include <alsa/asoundlib.h>
+#include <stdio.h>
+
+#include "core/os/mutex.h"
+#include "core/os/thread.h"
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverALSAMidi : public MIDIDriver {
+
+ Thread *thread;
+ Mutex *mutex;
+
+ Vector<snd_rawmidi_t *> connected_inputs;
+
+ bool exit_thread;
+
+ static void thread_func(void *p_udata);
+
+ void lock() const;
+ void unlock() const;
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ virtual PoolStringArray get_connected_inputs();
+
+ MIDIDriverALSAMidi();
+ virtual ~MIDIDriverALSAMidi();
+};
+
+#endif
+#endif
diff --git a/drivers/convex_decomp/b2d_decompose.h b/drivers/convex_decomp/b2d_decompose.h
index 068689d73d..b21792047e 100644
--- a/drivers/convex_decomp/b2d_decompose.h
+++ b/drivers/convex_decomp/b2d_decompose.h
@@ -31,8 +31,8 @@
#ifndef B2D_DECOMPOSE_H
#define B2D_DECOMPOSE_H
-#include "math_2d.h"
#include "vector.h"
+#include "vector2.h"
Vector<Vector<Vector2> > b2d_decompose(const Vector<Vector2> &p_polygon);
#endif // B2D_DECOMPOSE_H
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index 6e451eabcd..45d62e797f 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -35,8 +35,23 @@
#include "os/os.h"
#define kOutputBus 0
+#define kInputBus 1
#ifdef OSX_ENABLED
+OSStatus AudioDriverCoreAudio::input_device_address_cb(AudioObjectID inObjectID,
+ UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses,
+ void *inClientData) {
+ AudioDriverCoreAudio *driver = (AudioDriverCoreAudio *)inClientData;
+
+ // If our selected device is the Default call set_device to update the
+ // kAudioOutputUnitProperty_CurrentDevice property
+ if (driver->capture_device_name == "Default") {
+ driver->capture_set_device("Default");
+ }
+
+ return noErr;
+}
+
OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID,
UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses,
void *inClientData) {
@@ -52,7 +67,9 @@ OSStatus AudioDriverCoreAudio::output_device_address_cb(AudioObjectID inObjectID
}
#endif
-Error AudioDriverCoreAudio::init_device() {
+Error AudioDriverCoreAudio::init() {
+ mutex = Mutex::create();
+
AudioComponentDescription desc;
zeromem(&desc, sizeof(desc));
desc.componentType = kAudioUnitType_Output;
@@ -69,6 +86,21 @@ Error AudioDriverCoreAudio::init_device() {
OSStatus result = AudioComponentInstanceNew(comp, &audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
+#ifdef OSX_ENABLED
+ AudioObjectPropertyAddress prop;
+ prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+ prop.mScope = kAudioObjectPropertyScopeGlobal;
+ prop.mElement = kAudioObjectPropertyElementMaster;
+
+ 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;
zeromem(&strdesc, sizeof(strdesc));
@@ -90,7 +122,27 @@ Error AudioDriverCoreAudio::init_device() {
break;
}
- mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
+ 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));
strdesc.mFormatID = kAudioFormatLinearPCM;
@@ -105,7 +157,12 @@ Error AudioDriverCoreAudio::init_device() {
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, kOutputBus, &strdesc, sizeof(strdesc));
ERR_FAIL_COND_V(result != noErr, FAILED);
- int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
+ 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);
@@ -114,13 +171,15 @@ Error AudioDriverCoreAudio::init_device() {
ERR_FAIL_COND_V(result != noErr, FAILED);
#endif
- buffer_size = buffer_frames * channels;
+ 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;
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("CoreAudio: detected " + itos(channels) + " channels");
- print_line("CoreAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
- }
+ 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");
AURenderCallbackStruct callback;
zeromem(&callback, sizeof(AURenderCallbackStruct));
@@ -129,48 +188,18 @@ Error AudioDriverCoreAudio::init_device() {
result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
ERR_FAIL_COND_V(result != noErr, FAILED);
- result = AudioUnitInitialize(audio_unit);
+ 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);
- return OK;
-}
-
-Error AudioDriverCoreAudio::finish_device() {
- OSStatus result;
-
- if (active) {
- result = AudioOutputUnitStop(audio_unit);
- ERR_FAIL_COND_V(result != noErr, FAILED);
-
- active = false;
- }
-
- result = AudioUnitUninitialize(audio_unit);
+ result = AudioUnitInitialize(audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
return OK;
}
-Error AudioDriverCoreAudio::init() {
- OSStatus result;
-
- mutex = Mutex::create();
- active = false;
- channels = 2;
-
-#ifdef OSX_ENABLED
- AudioObjectPropertyAddress prop;
- prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
- prop.mScope = kAudioObjectPropertyScopeGlobal;
- prop.mElement = kAudioObjectPropertyElementMaster;
-
- result = AudioObjectAddPropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
- ERR_FAIL_COND_V(result != noErr, FAILED);
-#endif
-
- return init_device();
-};
-
OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
@@ -187,6 +216,8 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
return 0;
};
+ ad->start_counting_ticks();
+
for (unsigned int i = 0; i < ioData->mNumberBuffers; i++) {
AudioBuffer *abuf = &ioData->mBuffers[i];
@@ -208,11 +239,51 @@ OSStatus AudioDriverCoreAudio::output_callback(void *inRefCon,
};
};
+ ad->stop_counting_ticks();
ad->unlock();
return 0;
};
+OSStatus AudioDriverCoreAudio::input_callback(void *inRefCon,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber, UInt32 inNumberFrames,
+ AudioBufferList *ioData) {
+
+ AudioDriverCoreAudio *ad = (AudioDriverCoreAudio *)inRefCon;
+ if (!ad->active) {
+ return 0;
+ }
+
+ ad->lock();
+
+ AudioBufferList bufferList;
+ bufferList.mNumberBuffers = 1;
+ bufferList.mBuffers[0].mData = ad->input_buf.ptrw();
+ 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);
+ if (result == noErr) {
+ for (int i = 0; i < inNumberFrames * ad->capture_channels; i++) {
+ int32_t sample = ad->input_buf[i] << 16;
+ ad->input_buffer_write(sample);
+
+ if (ad->capture_channels == 1) {
+ // In case input device is single channel convert it to Stereo
+ ad->input_buffer_write(sample);
+ }
+ }
+ } else {
+ ERR_PRINT(("AudioUnitRender failed, code: " + itos(result)).utf8().get_data());
+ }
+
+ ad->unlock();
+
+ return result;
+}
+
void AudioDriverCoreAudio::start() {
if (!active) {
OSStatus result = AudioOutputUnitStart(audio_unit);
@@ -243,9 +314,96 @@ AudioDriver::SpeakerMode AudioDriverCoreAudio::get_speaker_mode() const {
return get_speaker_mode_by_total_channels(channels);
};
+void AudioDriverCoreAudio::lock() {
+ if (mutex)
+ mutex->lock();
+};
+
+void AudioDriverCoreAudio::unlock() {
+ if (mutex)
+ mutex->unlock();
+};
+
+bool AudioDriverCoreAudio::try_lock() {
+ if (mutex)
+ return mutex->try_lock() == OK;
+ return true;
+}
+
+void AudioDriverCoreAudio::finish() {
+ if (audio_unit) {
+ OSStatus result;
+
+ lock();
+
+ AURenderCallbackStruct callback;
+ zeromem(&callback, sizeof(AURenderCallbackStruct));
+ result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
+ if (result != noErr) {
+ ERR_PRINT("AudioUnitSetProperty failed");
+ }
+
+ if (active) {
+ result = AudioOutputUnitStop(audio_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioOutputUnitStop failed");
+ }
+
+ active = false;
+ }
+
+ result = AudioUnitUninitialize(audio_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioUnitUninitialize failed");
+ }
+
#ifdef OSX_ENABLED
+ AudioObjectPropertyAddress prop;
+ prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
+ prop.mScope = kAudioObjectPropertyScopeGlobal;
+ prop.mElement = kAudioObjectPropertyElementMaster;
-Array AudioDriverCoreAudio::get_device_list() {
+ result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
+ if (result != noErr) {
+ ERR_PRINT("AudioObjectRemovePropertyListener failed");
+ }
+#endif
+
+ result = AudioComponentInstanceDispose(audio_unit);
+ if (result != noErr) {
+ ERR_PRINT("AudioComponentInstanceDispose failed");
+ }
+
+ unlock();
+ }
+
+ if (mutex) {
+ memdelete(mutex);
+ mutex = NULL;
+ }
+}
+
+Error AudioDriverCoreAudio::capture_start() {
+
+ UInt32 flag = 1;
+ OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag));
+ ERR_FAIL_COND_V(result != noErr, FAILED);
+
+ 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);
+
+ return OK;
+}
+
+#ifdef OSX_ENABLED
+
+Array AudioDriverCoreAudio::_get_device_list(bool capture) {
Array list;
@@ -264,20 +422,20 @@ Array AudioDriverCoreAudio::get_device_list() {
UInt32 deviceCount = size / sizeof(AudioDeviceID);
for (UInt32 i = 0; i < deviceCount; i++) {
- prop.mScope = kAudioDevicePropertyScopeOutput;
+ prop.mScope = capture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
prop.mSelector = kAudioDevicePropertyStreamConfiguration;
AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size);
AudioBufferList *bufferList = (AudioBufferList *)malloc(size);
AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList);
- UInt32 outputChannelCount = 0;
+ UInt32 channelCount = 0;
for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
- outputChannelCount += bufferList->mBuffers[j].mNumberChannels;
+ channelCount += bufferList->mBuffers[j].mNumberChannels;
free(bufferList);
- if (outputChannelCount >= 1) {
+ if (channelCount >= 1) {
CFStringRef cfname;
size = sizeof(CFStringRef);
@@ -302,21 +460,11 @@ Array AudioDriverCoreAudio::get_device_list() {
return list;
}
-String AudioDriverCoreAudio::get_device() {
-
- return device_name;
-}
-
-void AudioDriverCoreAudio::set_device(String device) {
-
- device_name = device;
- if (!active) {
- return;
- }
+void AudioDriverCoreAudio::_set_device(const String &device, bool capture) {
AudioDeviceID deviceId;
bool found = false;
- if (device_name != "Default") {
+ if (device != "Default") {
AudioObjectPropertyAddress prop;
prop.mSelector = kAudioHardwarePropertyDevices;
@@ -330,20 +478,20 @@ void AudioDriverCoreAudio::set_device(String device) {
UInt32 deviceCount = size / sizeof(AudioDeviceID);
for (UInt32 i = 0; i < deviceCount && !found; i++) {
- prop.mScope = kAudioDevicePropertyScopeOutput;
+ prop.mScope = capture ? kAudioDevicePropertyScopeInput : kAudioDevicePropertyScopeOutput;
prop.mSelector = kAudioDevicePropertyStreamConfiguration;
AudioObjectGetPropertyDataSize(audioDevices[i], &prop, 0, NULL, &size);
AudioBufferList *bufferList = (AudioBufferList *)malloc(size);
AudioObjectGetPropertyData(audioDevices[i], &prop, 0, NULL, &size, bufferList);
- UInt32 outputChannelCount = 0;
+ UInt32 channelCount = 0;
for (UInt32 j = 0; j < bufferList->mNumberBuffers; j++)
- outputChannelCount += bufferList->mBuffers[j].mNumberChannels;
+ channelCount += bufferList->mBuffers[j].mNumberChannels;
free(bufferList);
- if (outputChannelCount >= 1) {
+ if (channelCount >= 1) {
CFStringRef cfname;
size = sizeof(CFStringRef);
@@ -356,7 +504,7 @@ void AudioDriverCoreAudio::set_device(String device) {
char *buffer = (char *)malloc(maxSize);
if (CFStringGetCString(cfname, buffer, maxSize, kCFStringEncodingUTF8)) {
String name = String(buffer) + " (" + itos(audioDevices[i]) + ")";
- if (name == device_name) {
+ if (name == device) {
deviceId = audioDevices[i];
found = true;
}
@@ -370,8 +518,10 @@ void AudioDriverCoreAudio::set_device(String device) {
}
if (!found) {
+ // If we haven't found the desired device get the system default one
UInt32 size = sizeof(AudioDeviceID);
- AudioObjectPropertyAddress property = { kAudioHardwarePropertyDefaultOutputDevice, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
+ UInt32 elem = capture ? kAudioHardwarePropertyDefaultInputDevice : kAudioHardwarePropertyDefaultOutputDevice;
+ AudioObjectPropertyAddress property = { elem, kAudioObjectPropertyScopeGlobal, kAudioObjectPropertyElementMaster };
OSStatus result = AudioObjectGetPropertyData(kAudioObjectSystemObject, &property, 0, NULL, &size, &deviceId);
ERR_FAIL_COND(result != noErr);
@@ -380,73 +530,69 @@ void AudioDriverCoreAudio::set_device(String device) {
}
if (found) {
- OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, 0, &deviceId, sizeof(AudioDeviceID));
+ OSStatus result = AudioUnitSetProperty(audio_unit, kAudioOutputUnitProperty_CurrentDevice, kAudioUnitScope_Global, capture ? kInputBus : kOutputBus, &deviceId, sizeof(AudioDeviceID));
ERR_FAIL_COND(result != noErr);
+
+ // Reset audio input to keep synchronisation.
+ input_position = 0;
+ input_size = 0;
}
}
-#endif
+Array AudioDriverCoreAudio::get_device_list() {
-void AudioDriverCoreAudio::lock() {
- if (mutex)
- mutex->lock();
-};
+ return _get_device_list();
+}
-void AudioDriverCoreAudio::unlock() {
- if (mutex)
- mutex->unlock();
-};
+String AudioDriverCoreAudio::get_device() {
-bool AudioDriverCoreAudio::try_lock() {
- if (mutex)
- return mutex->try_lock() == OK;
- return true;
+ return device_name;
}
-void AudioDriverCoreAudio::finish() {
- OSStatus result;
+void AudioDriverCoreAudio::set_device(String device) {
- finish_device();
+ device_name = device;
+ if (active) {
+ _set_device(device_name);
+ }
+}
-#ifdef OSX_ENABLED
- AudioObjectPropertyAddress prop;
- prop.mSelector = kAudioHardwarePropertyDefaultOutputDevice;
- prop.mScope = kAudioObjectPropertyScopeGlobal;
- prop.mElement = kAudioObjectPropertyElementMaster;
+void AudioDriverCoreAudio::capture_set_device(const String &p_name) {
- result = AudioObjectRemovePropertyListener(kAudioObjectSystemObject, &prop, &output_device_address_cb, this);
- if (result != noErr) {
- ERR_PRINT("AudioObjectRemovePropertyListener failed");
+ capture_device_name = p_name;
+ if (active) {
+ _set_device(capture_device_name, true);
}
-#endif
+}
- AURenderCallbackStruct callback;
- zeromem(&callback, sizeof(AURenderCallbackStruct));
- result = AudioUnitSetProperty(audio_unit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input, kOutputBus, &callback, sizeof(callback));
- if (result != noErr) {
- ERR_PRINT("AudioUnitSetProperty failed");
- }
+Array AudioDriverCoreAudio::capture_get_device_list() {
- if (mutex) {
- memdelete(mutex);
- mutex = NULL;
- }
-};
+ return _get_device_list(true);
+}
+
+String AudioDriverCoreAudio::capture_get_device() {
+
+ return capture_device_name;
+}
+
+#endif
AudioDriverCoreAudio::AudioDriverCoreAudio() {
+ audio_unit = NULL;
active = false;
mutex = NULL;
mix_rate = 0;
channels = 2;
+ capture_channels = 2;
- buffer_size = 0;
buffer_frames = 0;
samples_in.clear();
device_name = "Default";
-};
+ capture_device_name = "Default";
+}
AudioDriverCoreAudio::~AudioDriverCoreAudio(){};
diff --git a/drivers/coreaudio/audio_driver_coreaudio.h b/drivers/coreaudio/audio_driver_coreaudio.h
index c44e225521..d3f7c8d596 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.h
+++ b/drivers/coreaudio/audio_driver_coreaudio.h
@@ -48,15 +48,24 @@ class AudioDriverCoreAudio : public AudioDriver {
Mutex *mutex;
String device_name;
+ String capture_device_name;
int mix_rate;
unsigned int channels;
+ unsigned int capture_channels;
unsigned int buffer_frames;
- unsigned int buffer_size;
Vector<int32_t> samples_in;
+ Vector<int16_t> input_buf;
#ifdef OSX_ENABLED
+ Array _get_device_list(bool capture = false);
+ void _set_device(const String &device, bool capture = false);
+
+ static OSStatus input_device_address_cb(AudioObjectID inObjectID,
+ UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses,
+ void *inClientData);
+
static OSStatus output_device_address_cb(AudioObjectID inObjectID,
UInt32 inNumberAddresses, const AudioObjectPropertyAddress *inAddresses,
void *inClientData);
@@ -68,8 +77,11 @@ class AudioDriverCoreAudio : public AudioDriver {
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList *ioData);
- Error init_device();
- Error finish_device();
+ static OSStatus input_callback(void *inRefCon,
+ AudioUnitRenderActionFlags *ioActionFlags,
+ const AudioTimeStamp *inTimeStamp,
+ UInt32 inBusNumber, UInt32 inNumberFrames,
+ AudioBufferList *ioData);
public:
const char *get_name() const {
@@ -80,18 +92,27 @@ public:
virtual void start();
virtual int get_mix_rate() const;
virtual SpeakerMode get_speaker_mode() const;
-#ifdef OSX_ENABLED
- virtual Array get_device_list();
- virtual String get_device();
- virtual void set_device(String device);
-#endif
+
virtual void lock();
virtual void unlock();
virtual void finish();
+ virtual Error capture_start();
+ virtual Error capture_stop();
+
bool try_lock();
void stop();
+#ifdef OSX_ENABLED
+ virtual Array get_device_list();
+ virtual String get_device();
+ virtual void set_device(String device);
+
+ virtual Array capture_get_device_list();
+ virtual void capture_set_device(const String &p_name);
+ virtual String capture_get_device();
+#endif
+
AudioDriverCoreAudio();
~AudioDriverCoreAudio();
};
diff --git a/drivers/coremidi/SCsub b/drivers/coremidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/coremidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/coremidi/core_midi.cpp b/drivers/coremidi/core_midi.cpp
new file mode 100644
index 0000000000..6d4624e05b
--- /dev/null
+++ b/drivers/coremidi/core_midi.cpp
@@ -0,0 +1,124 @@
+/*************************************************************************/
+/* core_midi.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef COREMIDI_ENABLED
+
+#include "core_midi.h"
+#include "print_string.h"
+
+#include <CoreAudio/HostTime.h>
+#include <CoreServices/CoreServices.h>
+
+void MIDIDriverCoreMidi::read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con) {
+ MIDIPacket *packet = const_cast<MIDIPacket *>(packet_list->packet);
+ for (int i = 0; i < packet_list->numPackets; i++) {
+ receive_input_packet(packet->timeStamp, packet->data, packet->length);
+ packet = MIDIPacketNext(packet);
+ }
+}
+
+Error MIDIDriverCoreMidi::open() {
+
+ CFStringRef name = CFStringCreateWithCString(NULL, "Godot", kCFStringEncodingASCII);
+ OSStatus result = MIDIClientCreate(name, NULL, NULL, &client);
+ CFRelease(name);
+ if (result != noErr) {
+ ERR_PRINTS("MIDIClientCreate failed: " + String(GetMacOSStatusErrorString(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)));
+ return ERR_CANT_OPEN;
+ }
+
+ int sources = MIDIGetNumberOfSources();
+ for (int i = 0; i < sources; i++) {
+
+ MIDIEndpointRef source = MIDIGetSource(i);
+ if (source != NULL) {
+ MIDIPortConnectSource(port_in, source, (void *)this);
+ connected_sources.insert(i, source);
+ }
+ }
+
+ return OK;
+}
+
+void MIDIDriverCoreMidi::close() {
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ MIDIEndpointRef source = connected_sources[i];
+ MIDIPortDisconnectSource(port_in, source);
+ }
+ connected_sources.clear();
+
+ if (port_in != 0) {
+ MIDIPortDispose(port_in);
+ port_in = 0;
+ }
+
+ if (client != 0) {
+ MIDIClientDispose(client);
+ client = 0;
+ }
+}
+
+PoolStringArray MIDIDriverCoreMidi::get_connected_inputs() {
+
+ PoolStringArray list;
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ MIDIEndpointRef source = connected_sources[i];
+ CFStringRef ref = NULL;
+ char name[256];
+
+ MIDIObjectGetStringProperty(source, kMIDIPropertyDisplayName, &ref);
+ CFStringGetCString(ref, name, sizeof(name), kCFStringEncodingUTF8);
+ CFRelease(ref);
+
+ list.push_back(name);
+ }
+
+ return list;
+}
+
+MIDIDriverCoreMidi::MIDIDriverCoreMidi() {
+
+ client = 0;
+}
+
+MIDIDriverCoreMidi::~MIDIDriverCoreMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/coremidi/core_midi.h b/drivers/coremidi/core_midi.h
new file mode 100644
index 0000000000..c6b443764f
--- /dev/null
+++ b/drivers/coremidi/core_midi.h
@@ -0,0 +1,63 @@
+/*************************************************************************/
+/* core_midi.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef COREMIDI_ENABLED
+
+#ifndef CORE_MIDI_H
+#define CORE_MIDI_H
+
+#include <stdio.h>
+
+#include <CoreMIDI/CoreMIDI.h>
+
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverCoreMidi : public MIDIDriver {
+
+ MIDIClientRef client;
+ MIDIPortRef port_in;
+
+ Vector<MIDIEndpointRef> connected_sources;
+
+ static void read(const MIDIPacketList *packet_list, void *read_proc_ref_con, void *src_conn_ref_con);
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ PoolStringArray get_connected_inputs();
+
+ MIDIDriverCoreMidi();
+ virtual ~MIDIDriverCoreMidi();
+};
+
+#endif
+#endif
diff --git a/drivers/dummy/rasterizer_dummy.h b/drivers/dummy/rasterizer_dummy.h
index 312d5aa378..0381d3f0c1 100644
--- a/drivers/dummy/rasterizer_dummy.h
+++ b/drivers/dummy/rasterizer_dummy.h
@@ -67,7 +67,7 @@ public:
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) {}
- void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {}
+ void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {}
void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {}
@@ -154,7 +154,8 @@ public:
ERR_FAIL_COND_V(!texture, RID());
return texture_owner.make_rid(texture);
}
- void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) {
+
+ void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type = VS::TEXTURE_TYPE_2D, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT) {
DummyTexture *t = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!t);
t->width = p_width;
@@ -164,7 +165,7 @@ public:
t->image = Ref<Image>(memnew(Image));
t->image->create(p_width, p_height, false, p_format);
}
- void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) {
+ void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_level) {
DummyTexture *t = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!t);
t->width = p_image->get_width();
@@ -173,7 +174,7 @@ public:
t->image->create(t->width, t->height, false, t->format, p_image->get_data());
}
- void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) {
+ void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_level) {
DummyTexture *t = texture_owner.get(p_texture);
ERR_FAIL_COND(!t);
@@ -186,7 +187,7 @@ public:
t->image->blit_rect(p_image, Rect2(src_x, src_y, src_w, src_h), Vector2(dst_x, dst_y));
}
- Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const {
+ Ref<Image> texture_get_data(RID p_texture, int p_level) const {
DummyTexture *t = texture_owner.getornull(p_texture);
ERR_FAIL_COND_V(!t, Ref<Image>());
return t->image;
@@ -206,10 +207,13 @@ public:
ERR_FAIL_COND_V(!t, Image::FORMAT_RGB8);
return t->format;
}
+
+ VisualServer::TextureType texture_get_type(RID p_texture) const { return VS::TEXTURE_TYPE_2D; }
uint32_t texture_get_texid(RID p_texture) const { return 0; }
uint32_t texture_get_width(RID p_texture) const { return 0; }
uint32_t texture_get_height(RID p_texture) const { return 0; }
- void texture_set_size_override(RID p_texture, int p_width, int p_height) {}
+ uint32_t texture_get_depth(RID p_texture) const { return 0; }
+ void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth_3d) {}
void texture_set_path(RID p_texture, const String &p_path) {
DummyTexture *t = texture_owner.getornull(p_texture);
@@ -235,6 +239,7 @@ public:
void textures_keep_original(bool p_enable) {}
void texture_set_proxy(RID p_proxy, RID p_base) {}
+ void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {}
/* SKY API */
@@ -288,7 +293,7 @@ public:
ERR_FAIL_COND(!m);
m->surfaces.push_back(DummySurface());
- DummySurface *s = &m->surfaces[m->surfaces.size() - 1];
+ DummySurface *s = &m->surfaces.write[m->surfaces.size() - 1];
s->format = p_format;
s->primitive = p_primitive;
s->array = p_array;
@@ -408,19 +413,23 @@ public:
virtual RID multimesh_create() { return RID(); }
- void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format) {}
+ void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data = VS::MULTIMESH_CUSTOM_DATA_NONE) {}
int multimesh_get_instance_count(RID p_multimesh) const { return 0; }
void multimesh_set_mesh(RID p_multimesh, RID p_mesh) {}
void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) {}
void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {}
void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {}
+ void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {}
RID multimesh_get_mesh(RID p_multimesh) const { return RID(); }
Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const { return Transform(); }
Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const { return Transform2D(); }
Color multimesh_instance_get_color(RID p_multimesh, int p_index) const { return Color(); }
+ Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const { return Color(); }
+
+ void multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array) {}
void multimesh_set_visible_instances(RID p_multimesh, int p_visible) {}
int multimesh_get_visible_instances(RID p_multimesh) const { return 0; }
@@ -772,7 +781,7 @@ public:
void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale) {}
void initialize() {}
- void begin_frame() {}
+ void begin_frame(double frame_step) {}
void set_current_render_target(RID p_render_target) {}
void restore_render_target() {}
void clear_render_target(const Color &p_color) {}
@@ -780,6 +789,10 @@ public:
void end_frame(bool p_swap_buffers) {}
void finalize() {}
+ static Error is_viable() {
+ return OK;
+ }
+
static Rasterizer *_create_current() {
return memnew(RasterizerDummy);
}
diff --git a/drivers/dummy/texture_loader_dummy.cpp b/drivers/dummy/texture_loader_dummy.cpp
index 6d3e176bbb..b099019d17 100644
--- a/drivers/dummy/texture_loader_dummy.cpp
+++ b/drivers/dummy/texture_loader_dummy.cpp
@@ -45,10 +45,6 @@ RES ResourceFormatDummyTexture::load(const String &p_path, const String &p_origi
dstbuff.resize(rowsize * height);
- PoolVector<uint8_t>::Write dstbuff_write = dstbuff.write();
-
- uint8_t *data = dstbuff_write.ptr();
-
uint8_t **row_p = memnew_arr(uint8_t *, height);
for (unsigned int i = 0; i < height; i++) {
diff --git a/drivers/gles2/rasterizer_canvas_gles2.cpp b/drivers/gles2/rasterizer_canvas_gles2.cpp
index cc8e3277b9..9a9ede761a 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.cpp
+++ b/drivers/gles2/rasterizer_canvas_gles2.cpp
@@ -54,11 +54,28 @@ void RasterizerCanvasGLES2::_set_uniforms() {
state.canvas_shader.set_uniform(CanvasShaderGLES2::EXTRA_MATRIX, state.uniforms.extra_matrix);
state.canvas_shader.set_uniform(CanvasShaderGLES2::FINAL_MODULATE, state.uniforms.final_modulate);
+
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::TIME, storage->frame.time[0]);
+
+ if (storage->frame.current_rt) {
+ 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;
+
+ state.canvas_shader.set_uniform(CanvasShaderGLES2::SCREEN_PIXEL_SIZE, screen_pixel_size);
+ }
}
void RasterizerCanvasGLES2::canvas_begin() {
+ state.canvas_shader.bind();
+ if (storage->frame.current_rt) {
+ glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
+ glColorMask(1, 1, 1, 1);
+ }
+
if (storage->frame.clear_request) {
+ glColorMask(true, true, true, true);
glClearColor(storage->frame.clear_request_color.r,
storage->frame.clear_request_color.g,
storage->frame.clear_request_color.b,
@@ -67,10 +84,12 @@ void RasterizerCanvasGLES2::canvas_begin() {
storage->frame.clear_request = false;
}
+ /*
if (storage->frame.current_rt) {
glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
glColorMask(1, 1, 1, 1);
}
+ */
reset_canvas();
@@ -133,18 +152,22 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
state.current_tex = RID();
state.current_tex_ptr = NULL;
- glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
} else {
texture = texture->get_ptr();
+ if (texture->redraw_if_visible) {
+ VisualServerRaster::redraw_request();
+ }
+
if (texture->render_target) {
texture->render_target->used_in_frame = true;
}
- glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
glBindTexture(GL_TEXTURE_2D, texture->tex_id);
state.current_tex = p_texture;
@@ -156,7 +179,7 @@ RasterizerStorageGLES2::Texture *RasterizerCanvasGLES2::_bind_canvas_texture(con
state.current_tex = RID();
state.current_tex_ptr = NULL;
- glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
}
@@ -308,7 +331,7 @@ void RasterizerCanvasGLES2::_draw_gui_primitive(int p_points, const Vector2 *p_v
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
-void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip) {
+void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material) {
int command_count = p_item->commands.size();
Item::Command **commands = p_item->commands.ptrw();
@@ -325,9 +348,10 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
- state.canvas_shader.bind();
-
- _set_uniforms();
+ if (state.canvas_shader.bind()) {
+ _set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
_bind_canvas_texture(RID(), RID());
@@ -355,7 +379,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
_draw_gui_primitive(4, verts, NULL, NULL);
}
-
} break;
case Item::Command::TYPE_RECT: {
@@ -369,8 +392,10 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
- if (state.canvas_shader.bind())
+ if (state.canvas_shader.bind()) {
_set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(r->texture, r->normal_map);
@@ -405,8 +430,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
Rect2 dst_rect = Rect2(r->rect.position, r->rect.size);
- state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
-
if (dst_rect.size.width < 0) {
dst_rect.position.x += dst_rect.size.width;
dst_rect.size.width *= -1;
@@ -452,8 +475,10 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true);
- if (state.canvas_shader.bind())
+ if (state.canvas_shader.bind()) {
_set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
glDisableVertexAttribArray(VS::ARRAY_COLOR);
glVertexAttrib4fv(VS::ARRAY_COLOR, np->color.components);
@@ -461,7 +486,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
RasterizerStorageGLES2::Texture *tex = _bind_canvas_texture(np->texture, np->normal_map);
if (!tex) {
- print_line("TODO: ninepatch without texture");
+ // FIXME: Handle textureless ninepatch gracefully
+ WARN_PRINT("NinePatch without texture not supported yet in GLES2 backend, skipping.");
continue;
}
@@ -470,8 +496,16 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
// state.canvas_shader.set_uniform(CanvasShaderGLES2::MODELVIEW_MATRIX, state.uniforms.modelview_matrix);
state.canvas_shader.set_uniform(CanvasShaderGLES2::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ Rect2 source = np->source;
+ if (source.size.x == 0 && source.size.y == 0) {
+ source.size.x = tex->width;
+ source.size.y = tex->height;
+ }
+
// prepare vertex buffer
+ // this buffer contains [ POS POS UV UV ] *
+
float buffer[16 * 2 + 16 * 2];
{
@@ -481,106 +515,104 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
buffer[(0 * 4 * 4) + 0] = np->rect.position.x;
buffer[(0 * 4 * 4) + 1] = np->rect.position.y;
- buffer[(0 * 4 * 4) + 2] = np->source.position.x * texpixel_size.x;
- buffer[(0 * 4 * 4) + 3] = np->source.position.y * texpixel_size.y;
+ buffer[(0 * 4 * 4) + 2] = source.position.x * texpixel_size.x;
+ buffer[(0 * 4 * 4) + 3] = source.position.y * texpixel_size.y;
buffer[(0 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT];
buffer[(0 * 4 * 4) + 5] = np->rect.position.y;
- buffer[(0 * 4 * 4) + 6] = (np->source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
- buffer[(0 * 4 * 4) + 7] = np->source.position.y * texpixel_size.y;
+ buffer[(0 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
+ buffer[(0 * 4 * 4) + 7] = source.position.y * texpixel_size.y;
buffer[(0 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT];
buffer[(0 * 4 * 4) + 9] = np->rect.position.y;
- buffer[(0 * 4 * 4) + 10] = (np->source.position.x + np->source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
- buffer[(0 * 4 * 4) + 11] = np->source.position.y * texpixel_size.y;
+ buffer[(0 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
+ buffer[(0 * 4 * 4) + 11] = source.position.y * texpixel_size.y;
buffer[(0 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x;
buffer[(0 * 4 * 4) + 13] = np->rect.position.y;
- buffer[(0 * 4 * 4) + 14] = (np->source.position.x + np->source.size.x) * texpixel_size.x;
- buffer[(0 * 4 * 4) + 15] = np->source.position.y * texpixel_size.y;
+ buffer[(0 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x;
+ buffer[(0 * 4 * 4) + 15] = source.position.y * texpixel_size.y;
// second row
buffer[(1 * 4 * 4) + 0] = np->rect.position.x;
buffer[(1 * 4 * 4) + 1] = np->rect.position.y + np->margin[MARGIN_TOP];
- buffer[(1 * 4 * 4) + 2] = np->source.position.x * texpixel_size.x;
- buffer[(1 * 4 * 4) + 3] = (np->source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
+ buffer[(1 * 4 * 4) + 2] = source.position.x * texpixel_size.x;
+ buffer[(1 * 4 * 4) + 3] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
buffer[(1 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT];
buffer[(1 * 4 * 4) + 5] = np->rect.position.y + np->margin[MARGIN_TOP];
- buffer[(1 * 4 * 4) + 6] = (np->source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
- buffer[(1 * 4 * 4) + 7] = (np->source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
+ buffer[(1 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
+ buffer[(1 * 4 * 4) + 7] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
buffer[(1 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT];
buffer[(1 * 4 * 4) + 9] = np->rect.position.y + np->margin[MARGIN_TOP];
- buffer[(1 * 4 * 4) + 10] = (np->source.position.x + np->source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
- buffer[(1 * 4 * 4) + 11] = (np->source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
+ buffer[(1 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
+ buffer[(1 * 4 * 4) + 11] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
buffer[(1 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x;
buffer[(1 * 4 * 4) + 13] = np->rect.position.y + np->margin[MARGIN_TOP];
- buffer[(1 * 4 * 4) + 14] = (np->source.position.x + np->source.size.x) * texpixel_size.x;
- buffer[(1 * 4 * 4) + 15] = (np->source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
+ buffer[(1 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x;
+ buffer[(1 * 4 * 4) + 15] = (source.position.y + np->margin[MARGIN_TOP]) * texpixel_size.y;
// thrid row
buffer[(2 * 4 * 4) + 0] = np->rect.position.x;
buffer[(2 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM];
- buffer[(2 * 4 * 4) + 2] = np->source.position.x * texpixel_size.x;
- buffer[(2 * 4 * 4) + 3] = (np->source.position.y + np->source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
+ buffer[(2 * 4 * 4) + 2] = source.position.x * texpixel_size.x;
+ buffer[(2 * 4 * 4) + 3] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
buffer[(2 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT];
buffer[(2 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM];
- buffer[(2 * 4 * 4) + 6] = (np->source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
- buffer[(2 * 4 * 4) + 7] = (np->source.position.y + np->source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
+ buffer[(2 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
+ buffer[(2 * 4 * 4) + 7] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
buffer[(2 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT];
buffer[(2 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM];
- buffer[(2 * 4 * 4) + 10] = (np->source.position.x + np->source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
- buffer[(2 * 4 * 4) + 11] = (np->source.position.y + np->source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
+ buffer[(2 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
+ buffer[(2 * 4 * 4) + 11] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
buffer[(2 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x;
buffer[(2 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y - np->margin[MARGIN_BOTTOM];
- buffer[(2 * 4 * 4) + 14] = (np->source.position.x + np->source.size.x) * texpixel_size.x;
- buffer[(2 * 4 * 4) + 15] = (np->source.position.y + np->source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
+ buffer[(2 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x;
+ buffer[(2 * 4 * 4) + 15] = (source.position.y + source.size.y - np->margin[MARGIN_BOTTOM]) * texpixel_size.y;
// fourth row
buffer[(3 * 4 * 4) + 0] = np->rect.position.x;
buffer[(3 * 4 * 4) + 1] = np->rect.position.y + np->rect.size.y;
- buffer[(3 * 4 * 4) + 2] = np->source.position.x * texpixel_size.x;
- buffer[(3 * 4 * 4) + 3] = (np->source.position.y + np->source.size.y) * texpixel_size.y;
+ buffer[(3 * 4 * 4) + 2] = source.position.x * texpixel_size.x;
+ buffer[(3 * 4 * 4) + 3] = (source.position.y + source.size.y) * texpixel_size.y;
buffer[(3 * 4 * 4) + 4] = np->rect.position.x + np->margin[MARGIN_LEFT];
buffer[(3 * 4 * 4) + 5] = np->rect.position.y + np->rect.size.y;
- buffer[(3 * 4 * 4) + 6] = (np->source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
- buffer[(3 * 4 * 4) + 7] = (np->source.position.y + np->source.size.y) * texpixel_size.y;
+ buffer[(3 * 4 * 4) + 6] = (source.position.x + np->margin[MARGIN_LEFT]) * texpixel_size.x;
+ buffer[(3 * 4 * 4) + 7] = (source.position.y + source.size.y) * texpixel_size.y;
buffer[(3 * 4 * 4) + 8] = np->rect.position.x + np->rect.size.x - np->margin[MARGIN_RIGHT];
buffer[(3 * 4 * 4) + 9] = np->rect.position.y + np->rect.size.y;
- buffer[(3 * 4 * 4) + 10] = (np->source.position.x + np->source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
- buffer[(3 * 4 * 4) + 11] = (np->source.position.y + np->source.size.y) * texpixel_size.y;
+ buffer[(3 * 4 * 4) + 10] = (source.position.x + source.size.x - np->margin[MARGIN_RIGHT]) * texpixel_size.x;
+ buffer[(3 * 4 * 4) + 11] = (source.position.y + source.size.y) * texpixel_size.y;
buffer[(3 * 4 * 4) + 12] = np->rect.position.x + np->rect.size.x;
buffer[(3 * 4 * 4) + 13] = np->rect.position.y + np->rect.size.y;
- buffer[(3 * 4 * 4) + 14] = (np->source.position.x + np->source.size.x) * texpixel_size.x;
- buffer[(3 * 4 * 4) + 15] = (np->source.position.y + np->source.size.y) * texpixel_size.y;
-
- // print_line(String::num((np->source.position.y + np->source.size.y) * texpixel_size.y));
+ buffer[(3 * 4 * 4) + 14] = (source.position.x + source.size.x) * texpixel_size.x;
+ buffer[(3 * 4 * 4) + 15] = (source.position.y + source.size.y) * texpixel_size.y;
}
glBindBuffer(GL_ARRAY_BUFFER, data.ninepatch_vertices);
@@ -608,8 +640,10 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
- if (state.canvas_shader.bind())
+ if (state.canvas_shader.bind()) {
_set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
static const int num_points = 32;
@@ -637,8 +671,10 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true);
- if (state.canvas_shader.bind())
+ if (state.canvas_shader.bind()) {
_set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
RasterizerStorageGLES2::Texture *texture = _bind_canvas_texture(polygon->texture, polygon->normal_map);
@@ -656,8 +692,12 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
- if (state.canvas_shader.bind())
+ if (state.canvas_shader.bind()) {
_set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
+
+ _bind_canvas_texture(RID(), RID());
if (pline->triangles.size()) {
_draw_generic(GL_TRIANGLE_STRIP, pline->triangles.size(), pline->triangles.ptr(), NULL, pline->triangle_colors.ptr(), pline->triangle_colors.size() == 1);
@@ -685,8 +725,10 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, false);
state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, true);
- if (state.canvas_shader.bind())
+ if (state.canvas_shader.bind()) {
_set_uniforms();
+ state.canvas_shader.use_material((void *)p_material);
+ }
ERR_CONTINUE(primitive->points.size() < 1);
@@ -733,6 +775,9 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
int w = current_clip->final_clip_rect.size.x;
int h = current_clip->final_clip_rect.size.y;
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP])
+ y = current_clip->final_clip_rect.position.y;
+
glScissor(x, y, w, h);
reclip = false;
@@ -743,7 +788,8 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
} break;
default: {
- print_line("other");
+ // FIXME: Proper error handling if relevant
+ //print_line("other");
} break;
}
}
@@ -752,42 +798,6 @@ void RasterizerCanvasGLES2::_canvas_item_render_commands(Item *p_item, Item *cur
void RasterizerCanvasGLES2::_copy_texscreen(const Rect2 &p_rect) {
// This isn't really working yet, so disabling for now.
-
- /*
- glDisable(GL_BLEND);
-
- state.canvas_texscreen_used = true;
-
- Vector2 wh(storage->frame.current_rt->width, storage->frame.current_rt->height);
- Color copy_section(p_rect.position.x / wh.x, p_rect.position.y / wh.y, p_rect.size.x / wh.x, p_rect.size.y / wh.y);
-
- if (p_rect != Rect2()) {
- // only use section
-
- storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, true);
- }
-
-
- storage->shaders.copy.bind();
- storage->shaders.copy.set_uniform(CopyShaderGLES2::COPY_SECTION, copy_section);
-
- _bind_quad_buffer();
-
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->copy_screen_effect.fbo);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->color);
-
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
- glDisableVertexAttribArray(VS::ARRAY_VERTEX);
- glBindBuffer(GL_ARRAY_BUFFER, 0);
-
- glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
-
- state.canvas_shader.bind();
- _bind_canvas_texture(state.current_tex, state.current_normal);
-
- glEnable(GL_BLEND);
- */
}
void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform) {
@@ -821,7 +831,10 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
if (current_clip) {
glEnable(GL_SCISSOR_TEST);
- glScissor(current_clip->final_clip_rect.position.x, (rt_size.height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.height)), current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height);
+ int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y);
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP])
+ y = current_clip->final_clip_rect.position.y;
+ glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height);
} else {
glDisable(GL_SCISSOR_TEST);
}
@@ -840,10 +853,10 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
Item *material_owner = ci->material_owner ? ci->material_owner : ci;
RID material = material_owner->material;
+ RasterizerStorageGLES2::Material *material_ptr = storage->material_owner.getornull(material);
if (material != canvas_last_material || rebind_shader) {
- RasterizerStorageGLES2::Material *material_ptr = storage->material_owner.getornull(material);
RasterizerStorageGLES2::Shader *shader_ptr = NULL;
if (material_ptr) {
@@ -870,15 +883,15 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
}
int tc = material_ptr->textures.size();
- RID *textures = material_ptr->textures.ptrw();
+ Pair<StringName, RID> *textures = material_ptr->textures.ptrw();
ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = shader_ptr->texture_hints.ptrw();
for (int i = 0; i < tc; i++) {
- glActiveTexture(GL_TEXTURE2 + i);
+ glActiveTexture(GL_TEXTURE0 + i);
- RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(textures[i]);
+ RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(textures[i].second);
if (!t) {
@@ -903,12 +916,18 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
t = t->get_ptr();
+ if (t->redraw_if_visible) {
+ VisualServerRaster::redraw_request();
+ }
+
glBindTexture(t->target, t->tex_id);
}
+
} else {
state.canvas_shader.set_custom_shader(0);
state.canvas_shader.bind();
}
+ state.canvas_shader.use_material((void *)material_ptr);
shader_cache = shader_ptr;
@@ -918,7 +937,7 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
}
int blend_mode = shader_cache ? shader_cache->canvas_item.blend_mode : RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX;
- bool unshaded = true || (shader_cache && blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX);
+ bool unshaded = (shader_cache && blend_mode != RasterizerStorageGLES2::Shader::CanvasItem::BLEND_MODE_MIX);
bool reclip = false;
if (last_blend_mode != blend_mode) {
@@ -963,13 +982,16 @@ void RasterizerCanvasGLES2::canvas_render_items(Item *p_item_list, int p_z, cons
_set_uniforms();
- _canvas_item_render_commands(p_item_list, NULL, reclip);
+ _canvas_item_render_commands(p_item_list, NULL, reclip, material_ptr);
rebind_shader = true; // hacked in for now.
if (reclip) {
glEnable(GL_SCISSOR_TEST);
- glScissor(current_clip->final_clip_rect.position.x, (rt_size.height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.height)), current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height);
+ int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y);
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP])
+ y = current_clip->final_clip_rect.position.y;
+ glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height);
}
p_item_list = p_item_list->next;
@@ -1005,8 +1027,8 @@ void RasterizerCanvasGLES2::reset_canvas() {
// keeping this for now as there's nothing else that uses texture unit 2
// TODO ^
if (storage->frame.current_rt) {
- glActiveTexture(GL_TEXTURE0 + 2);
- glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color);
+ // glActiveTexture(GL_TEXTURE0 + 2);
+ // glBindTexture(GL_TEXTURE_2D, storage->frame.current_rt->copy_screen_effect.color);
}
glBindBuffer(GL_ARRAY_BUFFER, 0);
diff --git a/drivers/gles2/rasterizer_canvas_gles2.h b/drivers/gles2/rasterizer_canvas_gles2.h
index 4eab8c6038..cda3ec79e7 100644
--- a/drivers/gles2/rasterizer_canvas_gles2.h
+++ b/drivers/gles2/rasterizer_canvas_gles2.h
@@ -103,7 +103,7 @@ public:
_FORCE_INLINE_ void _draw_polygon(const int *p_indices, int p_index_count, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
_FORCE_INLINE_ void _draw_generic(GLuint p_primitive, int p_vertex_count, const Vector2 *p_vertices, const Vector2 *p_uvs, const Color *p_colors, bool p_singlecolor);
- _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip);
+ _FORCE_INLINE_ void _canvas_item_render_commands(Item *p_item, Item *current_clip, bool &reclip, RasterizerStorageGLES2::Material *p_material);
_FORCE_INLINE_ void _copy_texscreen(const Rect2 &p_rect);
virtual void canvas_render_items(Item *p_item_list, int p_z, const Color &p_modulate, Light *p_light, const Transform2D &p_base_transform);
diff --git a/drivers/gles2/rasterizer_gles2.cpp b/drivers/gles2/rasterizer_gles2.cpp
index ab48e682d6..efeab48ea2 100644
--- a/drivers/gles2/rasterizer_gles2.cpp
+++ b/drivers/gles2/rasterizer_gles2.cpp
@@ -136,28 +136,21 @@ RasterizerScene *RasterizerGLES2::get_scene() {
return scene;
}
-void RasterizerGLES2::initialize() {
-
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("Using GLES2 video driver");
- }
+Error RasterizerGLES2::is_viable() {
#ifdef GLAD_ENABLED
if (!gladLoadGL()) {
ERR_PRINT("Error initializing GLAD");
+ return ERR_UNAVAILABLE;
}
// GLVersion seems to be used for both GL and GL ES, so we need different version checks for them
#ifdef OPENGL_ENABLED // OpenGL 2.1 Profile required
- if (GLVersion.major < 2) {
-#else // OpenGL ES 3.0
+ if (GLVersion.major < 2 || (GLVersion.major == 2 && GLVersion.minor < 1)) {
+#else // OpenGL ES 2.0
if (GLVersion.major < 2) {
#endif
- ERR_PRINT("Your system's graphic drivers seem not to support OpenGL 2.1 / OpenGL ES 2.0, sorry :(\n"
- "Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault.");
- OS::get_singleton()->alert("Your system's graphic drivers seem not to support OpenGL 2.1 / OpenGL ES 2.0, sorry :(\n"
- "Godot Engine will self-destruct as soon as you acknowledge this error message.",
- "Fatal error: Insufficient OpenGL / GLES driver support");
+ return ERR_UNAVAILABLE;
}
#ifdef GLES_OVER_GL
@@ -183,14 +176,21 @@ void RasterizerGLES2::initialize() {
glGetFramebufferAttachmentParameteriv = glGetFramebufferAttachmentParameterivEXT;
glGenerateMipmap = glGenerateMipmapEXT;
} else {
- ERR_PRINT("Your system's graphic drivers seem not to support GL_ARB(EXT)_framebuffer_object OpenGL extension, sorry :(\n"
- "Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault.");
- OS::get_singleton()->alert("Your system's graphic drivers seem not to support GL_ARB(EXT)_framebuffer_object OpenGL extension, sorry :(\n"
- "Godot Engine will self-destruct as soon as you acknowledge this error message.",
- "Fatal error: Insufficient OpenGL / GLES driver support");
+ return ERR_UNAVAILABLE;
}
}
#endif
+
+#endif // GLAD_ENABLED
+
+ return OK;
+}
+
+void RasterizerGLES2::initialize() {
+
+ print_verbose("Using GLES2 video driver");
+
+#ifdef GLAD_ENABLED
if (true || OS::get_singleton()->is_stdout_verbose()) {
if (GLAD_GL_ARB_debug_output) {
glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
@@ -200,10 +200,9 @@ void RasterizerGLES2::initialize() {
print_line("OpenGL debugging not supported!");
}
}
-
#endif // GLAD_ENABLED
- // For debugging
+ // For debugging
#ifdef GLES_OVER_GL
if (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);
@@ -227,21 +226,14 @@ void RasterizerGLES2::initialize() {
scene->initialize();
}
-void RasterizerGLES2::begin_frame() {
- uint64_t tick = OS::get_singleton()->get_ticks_usec();
-
- double delta = double(tick - prev_ticks) / 1000000.0;
- delta *= Engine::get_singleton()->get_time_scale();
+void RasterizerGLES2::begin_frame(double frame_step) {
+ time_total += frame_step;
- time_total += delta;
-
- if (delta == 0) {
+ if (frame_step == 0) {
//to avoid hiccups
- delta = 0.001;
+ frame_step = 0.001;
}
- prev_ticks = tick;
-
// double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs");
// if (time_total > time_roll_over)
// time_total = 0; //roll over every day (should be customz
@@ -251,9 +243,7 @@ void RasterizerGLES2::begin_frame() {
storage->frame.time[2] = Math::fmod(time_total, 900);
storage->frame.time[3] = Math::fmod(time_total, 60);
storage->frame.count++;
- storage->frame.delta = delta;
-
- storage->frame.prev_tick = tick;
+ storage->frame.delta = frame_step;
storage->update_dirty_resources();
@@ -326,17 +316,33 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
canvas->canvas_begin();
RID texture = storage->texture_create();
- storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), VS::TEXTURE_FLAG_FILTER);
+ storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
storage->texture_set_data(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
Rect2 screenrect;
+ if (p_scale) {
+
+ if (window_w > window_h) {
+ //scale horizontally
+ screenrect.size.y = window_h;
+ screenrect.size.x = imgrect.size.x * window_h / imgrect.size.y;
+ screenrect.position.x = (window_w - screenrect.size.x) / 2;
+
+ } else {
+ //scale vertically
+ screenrect.size.x = window_w;
+ screenrect.size.y = imgrect.size.y * window_w / imgrect.size.x;
+ screenrect.position.y = (window_h - screenrect.size.y) / 2;
+ }
+ } else {
- screenrect = imgrect;
- screenrect.position += ((Size2(window_w, window_h) - screenrect.size) / 2.0).floor();
+ screenrect = imgrect;
+ screenrect.position += ((Size2(window_w, window_h) - screenrect.size) / 2.0).floor();
+ }
RasterizerStorageGLES2::Texture *t = storage->texture_owner.get(texture);
- glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
glBindTexture(GL_TEXTURE_2D, t->tex_id);
canvas->draw_generic_textured_rect(screenrect, Rect2(0, 0, 1, 1));
glBindTexture(GL_TEXTURE_2D, 0);
@@ -344,28 +350,7 @@ void RasterizerGLES2::set_boot_image(const Ref<Image> &p_image, const Color &p_c
storage->free(texture);
- if (OS::get_singleton()->is_layered_allowed()) {
- if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
-#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED)
- Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
- uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
- if (data) {
- glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
- OS::get_singleton()->swap_layered_buffer();
-
- return;
- }
-#endif
- } else {
- //clear alpha
- glColorMask(false, false, false, true);
- glClearColor(0, 0, 0, 1);
- glClear(GL_COLOR_BUFFER_BIT);
- glColorMask(true, true, true, true);
- }
- }
-
- OS::get_singleton()->swap_buffers();
+ end_frame(true);
}
void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen) {
@@ -378,21 +363,19 @@ void RasterizerGLES2::blit_render_target_to_screen(RID p_render_target, const Re
canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_TEXTURE_RECT, true);
canvas->state.canvas_shader.set_conditional(CanvasShaderGLES2::USE_UV_ATTRIBUTE, false);
+ canvas->state.canvas_shader.set_custom_shader(0);
canvas->state.canvas_shader.bind();
canvas->canvas_begin();
- canvas->state.canvas_shader.set_uniform(CanvasShaderGLES2::BLIT_PASS, true);
glDisable(GL_BLEND);
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
- glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
glBindTexture(GL_TEXTURE_2D, rt->color);
// TODO normals
canvas->draw_generic_textured_rect(p_screen_rect, Rect2(0, 0, 1, -1));
- canvas->state.canvas_shader.set_uniform(CanvasShaderGLES2::BLIT_PASS, false);
-
glBindTexture(GL_TEXTURE_2D, 0);
canvas->canvas_end();
}
@@ -452,7 +435,6 @@ RasterizerGLES2::RasterizerGLES2() {
scene->storage = storage;
storage->scene = scene;
- prev_ticks = 0;
time_total = 0;
}
diff --git a/drivers/gles2/rasterizer_gles2.h b/drivers/gles2/rasterizer_gles2.h
index 8d57275449..98c73b776b 100644
--- a/drivers/gles2/rasterizer_gles2.h
+++ b/drivers/gles2/rasterizer_gles2.h
@@ -43,7 +43,6 @@ class RasterizerGLES2 : public Rasterizer {
RasterizerCanvasGLES2 *canvas;
RasterizerSceneGLES2 *scene;
- uint64_t prev_ticks;
double time_total;
public:
@@ -54,7 +53,7 @@ public:
virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale);
virtual void initialize();
- virtual void begin_frame();
+ virtual void begin_frame(double frame_step);
virtual void set_current_render_target(RID p_render_target);
virtual void restore_render_target();
virtual void clear_render_target(const Color &p_color);
@@ -62,9 +61,10 @@ public:
virtual void end_frame(bool p_swap_buffers);
virtual void finalize();
+ static Error is_viable();
static void make_current();
-
static void register_config();
+
RasterizerGLES2();
~RasterizerGLES2();
};
diff --git a/drivers/gles2/rasterizer_scene_gles2.cpp b/drivers/gles2/rasterizer_scene_gles2.cpp
index bb39cbcbd5..e21998d55e 100644
--- a/drivers/gles2/rasterizer_scene_gles2.cpp
+++ b/drivers/gles2/rasterizer_scene_gles2.cpp
@@ -28,38 +28,398 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "rasterizer_scene_gles2.h"
+#include "math/transform.h"
#include "math_funcs.h"
#include "os/os.h"
#include "project_settings.h"
#include "rasterizer_canvas_gles2.h"
#include "servers/visual/visual_server_raster.h"
+#include "vmap.h"
+
#ifndef GLES_OVER_GL
#define glClearDepth glClearDepthf
#endif
+static const GLenum _cube_side_enum[6] = {
+
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_X,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Y,
+ GL_TEXTURE_CUBE_MAP_NEGATIVE_Z,
+ GL_TEXTURE_CUBE_MAP_POSITIVE_Z,
+
+};
+
/* SHADOW ATLAS API */
RID RasterizerSceneGLES2::shadow_atlas_create() {
- return RID();
+ ShadowAtlas *shadow_atlas = memnew(ShadowAtlas);
+ shadow_atlas->fbo = 0;
+ shadow_atlas->depth = 0;
+ shadow_atlas->size = 0;
+ shadow_atlas->smallest_subdiv = 0;
+
+ for (int i = 0; i < 4; i++) {
+ shadow_atlas->size_order[i] = i;
+ }
+
+ return shadow_atlas_owner.make_rid(shadow_atlas);
}
void RasterizerSceneGLES2::shadow_atlas_set_size(RID p_atlas, int p_size) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_COND(p_size < 0);
+
+ p_size = next_power_of_2(p_size);
+
+ if (p_size == shadow_atlas->size)
+ return;
+
+ // erase the old atlast
+ if (shadow_atlas->fbo) {
+ glDeleteTextures(1, &shadow_atlas->depth);
+ glDeleteFramebuffers(1, &shadow_atlas->fbo);
+
+ shadow_atlas->fbo = 0;
+ shadow_atlas->depth = 0;
+ }
+
+ // erase shadow atlast references from lights
+ for (Map<RID, uint32_t>::Element *E = shadow_atlas->shadow_owners.front(); E; E = E->next()) {
+ LightInstance *li = light_instance_owner.getornull(E->key());
+ ERR_CONTINUE(!li);
+ li->shadow_atlases.erase(p_atlas);
+ }
+
+ shadow_atlas->shadow_owners.clear();
+
+ shadow_atlas->size = p_size;
+
+ if (shadow_atlas->size) {
+ glGenFramebuffers(1, &shadow_atlas->fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo);
+
+ // create a depth texture
+ glActiveTexture(GL_TEXTURE0);
+ glGenTextures(1, &shadow_atlas->depth);
+ glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, shadow_atlas->size, shadow_atlas->size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, shadow_atlas->depth, 0);
+
+ glViewport(0, 0, shadow_atlas->size, shadow_atlas->size);
+
+ glDepthMask(GL_TRUE);
+
+ glClearDepth(0.0f);
+ glClear(GL_DEPTH_BUFFER_BIT);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ }
}
void RasterizerSceneGLES2::shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND(!shadow_atlas);
+ ERR_FAIL_INDEX(p_quadrant, 4);
+ ERR_FAIL_INDEX(p_subdivision, 16384);
+
+ uint32_t subdiv = next_power_of_2(p_subdivision);
+ if (subdiv & 0xaaaaaaaa) { // sqrt(subdiv) must be integer
+ subdiv <<= 1;
+ }
+
+ subdiv = int(Math::sqrt((float)subdiv));
+
+ if (shadow_atlas->quadrants[p_quadrant].shadows.size() == subdiv)
+ return;
+
+ // erase all data from the quadrant
+ for (int i = 0; i < shadow_atlas->quadrants[p_quadrant].shadows.size(); i++) {
+ if (shadow_atlas->quadrants[p_quadrant].shadows[i].owner.is_valid()) {
+ shadow_atlas->shadow_owners.erase(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+
+ LightInstance *li = light_instance_owner.getornull(shadow_atlas->quadrants[p_quadrant].shadows[i].owner);
+ ERR_CONTINUE(!li);
+ li->shadow_atlases.erase(p_atlas);
+ }
+ }
+
+ shadow_atlas->quadrants[p_quadrant].shadows.resize(0);
+ shadow_atlas->quadrants[p_quadrant].shadows.resize(subdiv);
+ shadow_atlas->quadrants[p_quadrant].subdivision = subdiv;
+
+ // cache the smallest subdivision for faster allocations
+
+ shadow_atlas->smallest_subdiv = 1 << 30;
+
+ for (int i = 0; i < 4; i++) {
+ if (shadow_atlas->quadrants[i].subdivision) {
+ shadow_atlas->smallest_subdiv = MIN(shadow_atlas->smallest_subdiv, shadow_atlas->quadrants[i].subdivision);
+ }
+ }
+
+ if (shadow_atlas->smallest_subdiv == 1 << 30) {
+ shadow_atlas->smallest_subdiv = 0;
+ }
+
+ // re-sort the quadrants
+
+ int swaps = 0;
+ do {
+ swaps = 0;
+
+ for (int i = 0; i < 3; i++) {
+ if (shadow_atlas->quadrants[shadow_atlas->size_order[i]].subdivision < shadow_atlas->quadrants[shadow_atlas->size_order[i + 1]].subdivision) {
+ SWAP(shadow_atlas->size_order[i], shadow_atlas->size_order[i + 1]);
+ swaps++;
+ }
+ }
+
+ } while (swaps > 0);
+}
+
+bool RasterizerSceneGLES2::_shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow) {
+
+ for (int i = p_quadrant_count - 1; i >= 0; i--) {
+ int qidx = p_in_quadrants[i];
+
+ if (shadow_atlas->quadrants[qidx].subdivision == (uint32_t)p_current_subdiv) {
+ return false;
+ }
+
+ // look for an empty space
+
+ int sc = shadow_atlas->quadrants[qidx].shadows.size();
+
+ ShadowAtlas::Quadrant::Shadow *sarr = shadow_atlas->quadrants[qidx].shadows.ptrw();
+
+ int found_free_idx = -1; // found a free one
+ int found_used_idx = -1; // found an existing one, must steal it
+ uint64_t min_pass = 0; // pass of the existing one, try to use the least recently
+
+ for (int j = 0; j < sc; j++) {
+ if (!sarr[j].owner.is_valid()) {
+ found_free_idx = j;
+ break;
+ }
+
+ LightInstance *sli = light_instance_owner.getornull(sarr[j].owner);
+ ERR_CONTINUE(!sli);
+
+ if (sli->last_scene_pass != scene_pass) {
+
+ // was just allocated, don't kill it so soon, wait a bit...
+
+ if (p_tick - sarr[j].alloc_tick < shadow_atlas_realloc_tolerance_msec) {
+ continue;
+ }
+
+ if (found_used_idx == -1 || sli->last_scene_pass < min_pass) {
+ found_used_idx = j;
+ min_pass = sli->last_scene_pass;
+ }
+ }
+ }
+
+ if (found_free_idx == -1 && found_used_idx == -1) {
+ continue; // nothing found
+ }
+
+ if (found_free_idx == -1 && found_used_idx != -1) {
+ found_free_idx = found_used_idx;
+ }
+
+ r_quadrant = qidx;
+ r_shadow = found_free_idx;
+
+ return true;
+ }
+
+ return false;
}
bool RasterizerSceneGLES2::shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version) {
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_atlas);
+ ERR_FAIL_COND_V(!shadow_atlas, false);
+
+ LightInstance *li = light_instance_owner.getornull(p_light_intance);
+ ERR_FAIL_COND_V(!li, false);
+
+ if (shadow_atlas->size == 0 || shadow_atlas->smallest_subdiv == 0) {
+ return false;
+ }
+
+ uint32_t quad_size = shadow_atlas->size >> 1;
+ int desired_fit = MIN(quad_size / shadow_atlas->smallest_subdiv, next_power_of_2(quad_size * p_coverage));
+
+ int valid_quadrants[4];
+ int valid_quadrant_count = 0;
+ int best_size = -1;
+ int best_subdiv = -1;
+
+ for (int i = 0; i < 4; i++) {
+ int q = shadow_atlas->size_order[i];
+ int sd = shadow_atlas->quadrants[q].subdivision;
+
+ if (sd == 0) {
+ continue;
+ }
+
+ int max_fit = quad_size / sd;
+
+ if (best_size != -1 && max_fit > best_size) {
+ break; // what we asked for is bigger than this.
+ }
+
+ valid_quadrants[valid_quadrant_count] = q;
+ valid_quadrant_count++;
+
+ best_subdiv = sd;
+
+ if (max_fit >= desired_fit) {
+ best_size = max_fit;
+ }
+ }
+
+ ERR_FAIL_COND_V(valid_quadrant_count == 0, false); // no suitable block available
+
+ uint64_t tick = OS::get_singleton()->get_ticks_msec();
+
+ if (shadow_atlas->shadow_owners.has(p_light_intance)) {
+ // light was already known!
+
+ uint32_t key = shadow_atlas->shadow_owners[p_light_intance];
+ uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
+ uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ bool should_realloc = shadow_atlas->quadrants[q].subdivision != (uint32_t)best_subdiv && (shadow_atlas->quadrants[q].shadows[s].alloc_tick - tick > shadow_atlas_realloc_tolerance_msec);
+
+ bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version;
+
+ if (!should_realloc) {
+ shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
+ return should_redraw;
+ }
+
+ int new_quadrant;
+ int new_shadow;
+
+ // find a better place
+
+ if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) {
+ // found a better place
+
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
+ if (sh->owner.is_valid()) {
+ // it is take but invalid, so we can take it
+
+ shadow_atlas->shadow_owners.erase(sh->owner);
+ LightInstance *sli = light_instance_owner.get(sh->owner);
+ sli->shadow_atlases.erase(p_atlas);
+ }
+
+ // erase previous
+ shadow_atlas->quadrants[q].shadows.write[s].version = 0;
+ shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
+
+ sh->owner = p_light_intance;
+ sh->alloc_tick = tick;
+ sh->version = p_light_version;
+ li->shadow_atlases.insert(p_atlas);
+
+ // make a new key
+ key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
+ key |= new_shadow;
+
+ // update it in the map
+ shadow_atlas->shadow_owners[p_light_intance] = key;
+
+ // make it dirty, so we redraw
+ return true;
+ }
+
+ // no better place found, so we keep the current place
+
+ shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
+
+ return should_redraw;
+ }
+
+ int new_quadrant;
+ int new_shadow;
+
+ if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) {
+ // found a better place
+
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
+ if (sh->owner.is_valid()) {
+ // it is take but invalid, so we can take it
+
+ shadow_atlas->shadow_owners.erase(sh->owner);
+ LightInstance *sli = light_instance_owner.get(sh->owner);
+ sli->shadow_atlases.erase(p_atlas);
+ }
+
+ sh->owner = p_light_intance;
+ sh->alloc_tick = tick;
+ sh->version = p_light_version;
+ li->shadow_atlases.insert(p_atlas);
+
+ // make a new key
+ uint32_t key = new_quadrant << ShadowAtlas::QUADRANT_SHIFT;
+ key |= new_shadow;
+
+ // update it in the map
+ shadow_atlas->shadow_owners[p_light_intance] = key;
+
+ // make it dirty, so we redraw
+ return true;
+ }
+
return false;
}
void RasterizerSceneGLES2::set_directional_shadow_count(int p_count) {
+ directional_shadow.light_count = p_count;
+ directional_shadow.current_light = 0;
}
int RasterizerSceneGLES2::get_directional_light_shadow_size(RID p_light_intance) {
- return 0;
+
+ ERR_FAIL_COND_V(directional_shadow.light_count == 0, 0);
+
+ int shadow_size;
+
+ if (directional_shadow.light_count == 1) {
+ shadow_size = directional_shadow.size;
+ } else {
+ shadow_size = directional_shadow.size / 2; //more than 4 not supported anyway
+ }
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_intance);
+ ERR_FAIL_COND_V(!light_instance, 0);
+
+ switch (light_instance->light_ptr->directional_shadow_mode) {
+ case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL:
+ break; //none
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS:
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS:
+ shadow_size /= 2;
+ break;
+ }
+
+ return shadow_size;
}
//////////////////////////////////////////////////////
@@ -105,86 +465,183 @@ bool RasterizerSceneGLES2::reflection_probe_instance_postprocess_step(RID p_inst
RID RasterizerSceneGLES2::environment_create() {
- return RID();
+ Environment *env = memnew(Environment);
+
+ return environment_owner.make_rid(env);
}
void RasterizerSceneGLES2::environment_set_background(RID p_env, VS::EnvironmentBG p_bg) {
+
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+ env->bg_mode = p_bg;
}
void RasterizerSceneGLES2::environment_set_sky(RID p_env, RID p_sky) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->sky = p_sky;
}
void RasterizerSceneGLES2::environment_set_sky_custom_fov(RID p_env, float p_scale) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->sky_custom_fov = p_scale;
}
void RasterizerSceneGLES2::environment_set_bg_color(RID p_env, const Color &p_color) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->bg_color = p_color;
}
void RasterizerSceneGLES2::environment_set_bg_energy(RID p_env, float p_energy) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->bg_energy = p_energy;
}
void RasterizerSceneGLES2::environment_set_canvas_max_layer(RID p_env, int p_max_layer) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->canvas_max_layer = p_max_layer;
}
void RasterizerSceneGLES2::environment_set_ambient_light(RID p_env, const Color &p_color, float p_energy, float p_sky_contribution) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
+
+ env->ambient_color = p_color;
+ env->ambient_energy = p_energy;
+ env->ambient_sky_contribution = p_sky_contribution;
}
void RasterizerSceneGLES2::environment_set_dof_blur_far(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
void RasterizerSceneGLES2::environment_set_dof_blur_near(RID p_env, bool p_enable, float p_distance, float p_transition, float p_amount, VS::EnvironmentDOFBlurQuality p_quality) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
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) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
void RasterizerSceneGLES2::environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
void RasterizerSceneGLES2::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) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
-void RasterizerSceneGLES2::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
+void RasterizerSceneGLES2::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
void RasterizerSceneGLES2::environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
void RasterizerSceneGLES2::environment_set_adjustment(RID p_env, bool p_enable, float p_brightness, float p_contrast, float p_saturation, RID p_ramp) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
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);
}
void RasterizerSceneGLES2::environment_set_fog_depth(RID p_env, bool p_enable, float p_depth_begin, float p_depth_curve, bool p_transmit, float p_transmit_curve) {
+ Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND(!env);
}
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);
}
bool RasterizerSceneGLES2::is_environment(RID p_env) {
- return false;
+ return environment_owner.owns(p_env);
}
VS::EnvironmentBG RasterizerSceneGLES2::environment_get_background(RID p_env) {
- return VS::ENV_BG_CLEAR_COLOR;
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, VS::ENV_BG_MAX);
+
+ return env->bg_mode;
}
int RasterizerSceneGLES2::environment_get_canvas_max_layer(RID p_env) {
- return 0;
+ const Environment *env = environment_owner.getornull(p_env);
+ ERR_FAIL_COND_V(!env, -1);
+
+ return env->canvas_max_layer;
}
RID RasterizerSceneGLES2::light_instance_create(RID p_light) {
- return RID();
+
+ LightInstance *light_instance = memnew(LightInstance);
+
+ light_instance->last_scene_pass = 0;
+
+ light_instance->light = p_light;
+ light_instance->light_ptr = storage->light_owner.getornull(p_light);
+
+ ERR_FAIL_COND_V(!light_instance->light_ptr, RID());
+
+ light_instance->self = light_instance_owner.make_rid(light_instance);
+
+ return light_instance->self;
}
void RasterizerSceneGLES2::light_instance_set_transform(RID p_light_instance, const Transform &p_transform) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->transform = p_transform;
}
void RasterizerSceneGLES2::light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ if (light_instance->light_ptr->type != VS::LIGHT_DIRECTIONAL) {
+ p_pass = 0;
+ }
+
+ ERR_FAIL_INDEX(p_pass, 4);
+
+ light_instance->shadow_transform[p_pass].camera = p_projection;
+ light_instance->shadow_transform[p_pass].transform = p_transform;
+ light_instance->shadow_transform[p_pass].farplane = p_far;
+ light_instance->shadow_transform[p_pass].split = p_split;
+ light_instance->shadow_transform[p_pass].bias_scale = p_bias_scale;
}
void RasterizerSceneGLES2::light_instance_mark_visible(RID p_light_instance) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light_instance);
+ ERR_FAIL_COND(!light_instance);
+
+ light_instance->last_scene_pass = scene_pass;
}
//////////////////////
@@ -206,13 +663,1704 @@ void RasterizerSceneGLES2::gi_probe_instance_set_bounds(RID p_probe, const Vecto
////////////////////////////
////////////////////////////
+void RasterizerSceneGLES2::_add_geometry(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass) {
+
+ RasterizerStorageGLES2::Material *material = NULL;
+ RID material_src;
+
+ if (p_instance->material_override.is_valid()) {
+ material_src = p_instance->material_override;
+ } else if (p_material >= 0) {
+ material_src = p_instance->materials[p_material];
+ } else {
+ material_src = p_geometry->material;
+ }
+
+ if (material_src.is_valid()) {
+ material = storage->material_owner.getornull(material_src);
+
+ if (!material->shader || !material->shader->valid) {
+ material = NULL;
+ }
+ }
+
+ if (!material) {
+ material = storage->material_owner.getptr(default_material);
+ }
+
+ ERR_FAIL_COND(!material);
+
+ _add_geometry_with_material(p_geometry, p_instance, p_owner, material, p_depth_pass, p_shadow_pass);
+
+ while (material->next_pass.is_valid()) {
+ material = storage->material_owner.getornull(material->next_pass);
+
+ if (!material || !material->shader || !material->shader->valid) {
+ break;
+ }
+
+ _add_geometry_with_material(p_geometry, p_instance, p_owner, material, p_depth_pass, p_shadow_pass);
+ }
+}
+void RasterizerSceneGLES2::_add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass) {
+
+ bool has_base_alpha = (p_material->shader->spatial.uses_alpha && !p_material->shader->spatial.uses_alpha_scissor) || p_material->shader->spatial.uses_screen_texture || p_material->shader->spatial.uses_depth_texture;
+ bool has_blend_alpha = p_material->shader->spatial.blend_mode != RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX;
+ bool has_alpha = has_base_alpha || has_blend_alpha;
+
+ // TODO add this stuff
+ // bool mirror = p_instance->mirror;
+ // bool no_cull = false;
+
+ RenderList::Element *e = has_alpha ? render_list.add_alpha_element() : render_list.add_element();
+
+ if (!e) {
+ return;
+ }
+
+ e->geometry = p_geometry;
+ e->material = p_material;
+ e->instance = p_instance;
+ e->owner = p_owner;
+ e->sort_key = 0;
+
+ // TODO check render pass of geometry
+
+ // TODO check directional light flag
+
+ if (p_depth_pass) {
+ // if we are in the depth pass we can sort out a few things to improve performance
+
+ if (has_blend_alpha || p_material->shader->spatial.uses_depth_texture || (has_base_alpha && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS)) {
+ return;
+ }
+
+ if (p_material->shader->spatial.uses_alpha_scissor && !p_material->shader->spatial.writes_modelview_or_projection && !p_material->shader->spatial.uses_vertex && !p_material->shader->spatial.uses_discard && p_material->shader->spatial.depth_draw_mode != RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS) {
+
+ // shader doesn't use discard or writes a custom vertex position,
+ // so we can use a stripped down shader instead
+
+ // TODO twosided and worldcoord stuff
+
+ p_material = storage->material_owner.getptr(default_material_twosided);
+ }
+
+ has_alpha = false;
+ }
+
+ e->sort_key |= uint64_t(e->geometry->index) << RenderList::SORT_KEY_GEOMETRY_INDEX_SHIFT;
+ e->sort_key |= uint64_t(e->instance->base_type) << RenderList::SORT_KEY_GEOMETRY_TYPE_SHIFT;
+
+ if (p_material->shader->spatial.unshaded) {
+ e->sort_key |= SORT_KEY_UNSHADED_FLAG;
+ }
+
+ if (!p_depth_pass) {
+ e->sort_key |= uint64_t(e->material->index) << RenderList::SORT_KEY_MATERIAL_INDEX_SHIFT;
+
+ e->sort_key |= uint64_t(p_material->render_priority + 128) << RenderList::SORT_KEY_PRIORITY_SHIFT;
+ } else {
+ // TODO
+ }
+
+ if (p_material->shader->spatial.uses_time) {
+ VisualServerRaster::redraw_request();
+ }
+}
+
+void RasterizerSceneGLES2::_fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass) {
+
+ for (int i = 0; i < p_cull_count; i++) {
+
+ InstanceBase *instance = p_cull_result[i];
+
+ switch (instance->base_type) {
+
+ case VS::INSTANCE_MESH: {
+
+ RasterizerStorageGLES2::Mesh *mesh = storage->mesh_owner.getornull(instance->base);
+ ERR_CONTINUE(!mesh);
+
+ int num_surfaces = mesh->surfaces.size();
+
+ for (int i = 0; i < num_surfaces; i++) {
+ int material_index = instance->materials[i].is_valid() ? i : -1;
+
+ RasterizerStorageGLES2::Surface *surface = mesh->surfaces[i];
+
+ _add_geometry(surface, instance, NULL, material_index, p_depth_pass, p_shadow_pass);
+ }
+
+ } break;
+
+ case VS::INSTANCE_MULTIMESH: {
+ RasterizerStorageGLES2::MultiMesh *multi_mesh = storage->multimesh_owner.getptr(instance->base);
+ ERR_CONTINUE(!multi_mesh);
+
+ if (multi_mesh->size == 0 || multi_mesh->visible_instances == 0)
+ continue;
+
+ RasterizerStorageGLES2::Mesh *mesh = storage->mesh_owner.getptr(multi_mesh->mesh);
+ if (!mesh)
+ continue;
+
+ int ssize = mesh->surfaces.size();
+
+ for (int i = 0; i < ssize; i++) {
+ RasterizerStorageGLES2::Surface *s = mesh->surfaces[i];
+ _add_geometry(s, instance, multi_mesh, -1, p_depth_pass, p_shadow_pass);
+ }
+ } break;
+
+ case VS::INSTANCE_IMMEDIATE: {
+ RasterizerStorageGLES2::Immediate *im = storage->immediate_owner.getptr(instance->base);
+ ERR_CONTINUE(!im);
+
+ _add_geometry(im, instance, NULL, -1, p_depth_pass, p_shadow_pass);
+
+ } break;
+
+ default: {
+
+ } break;
+ }
+ }
+}
+
+static const GLenum gl_primitive[] = {
+ GL_POINTS,
+ GL_LINES,
+ GL_LINE_STRIP,
+ GL_LINE_LOOP,
+ GL_TRIANGLES,
+ GL_TRIANGLE_STRIP,
+ GL_TRIANGLE_FAN
+};
+
+void RasterizerSceneGLES2::_setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size) {
+
+ // material parameters
+
+ state.scene_shader.set_custom_shader(p_material->shader->custom_code_id);
+
+ state.scene_shader.bind();
+
+ if (p_material->shader->spatial.no_depth_test) {
+ glDisable(GL_DEPTH_TEST);
+ } else {
+ glEnable(GL_DEPTH_TEST);
+ }
+
+ switch (p_material->shader->spatial.depth_draw_mode) {
+ case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS:
+ case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_OPAQUE: {
+
+ glDepthMask(!p_alpha_pass);
+ } break;
+ case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_ALWAYS: {
+ glDepthMask(GL_TRUE);
+ } break;
+ case RasterizerStorageGLES2::Shader::Spatial::DEPTH_DRAW_NEVER: {
+ glDepthMask(GL_FALSE);
+ } break;
+ }
+
+ // TODO whyyyyy????
+ p_reverse_cull = true;
+
+ switch (p_material->shader->spatial.cull_mode) {
+ case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_DISABLED: {
+ glDisable(GL_CULL_FACE);
+ } break;
+
+ case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_BACK: {
+ glEnable(GL_CULL_FACE);
+ glCullFace(p_reverse_cull ? GL_FRONT : GL_BACK);
+ } break;
+ case RasterizerStorageGLES2::Shader::Spatial::CULL_MODE_FRONT: {
+ glEnable(GL_CULL_FACE);
+ glCullFace(p_reverse_cull ? GL_BACK : GL_FRONT);
+ } break;
+ }
+
+ int tc = p_material->textures.size();
+ Pair<StringName, RID> *textures = p_material->textures.ptrw();
+
+ ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptrw();
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::SKELETON_TEXTURE_SIZE, p_skeleton_tex_size);
+
+ for (int i = 0; i < tc; i++) {
+
+ glActiveTexture(GL_TEXTURE0 + i);
+
+ RasterizerStorageGLES2::Texture *t = storage->texture_owner.getornull(textures[i].second);
+
+ if (!t) {
+
+ switch (texture_hints[i]) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO:
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: {
+ glBindTexture(GL_TEXTURE_2D, storage->resources.black_tex);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
+ glBindTexture(GL_TEXTURE_2D, storage->resources.aniso_tex);
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: {
+ glBindTexture(GL_TEXTURE_2D, storage->resources.normal_tex);
+ } break;
+ default: {
+ glBindTexture(GL_TEXTURE_2D, storage->resources.white_tex);
+ } break;
+ }
+
+ continue;
+ }
+
+ t = t->get_ptr();
+
+ glBindTexture(t->target, t->tex_id);
+ }
+ state.scene_shader.use_material((void *)p_material);
+}
+
+void RasterizerSceneGLES2::_setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton) {
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON, p_skeleton != NULL);
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, !storage->config.float_texture_supported);
+ // state.scene_shader.set_conditional(SceneShaderGLES2::USE_SKELETON_SOFTWARE, true);
+
+ switch (p_element->instance->base_type) {
+
+ case VS::INSTANCE_MESH: {
+ RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, s->attribs[VS::ARRAY_COLOR].enabled);
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, s->attribs[VS::ARRAY_TEX_UV].enabled);
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, s->attribs[VS::ARRAY_TEX_UV2].enabled);
+
+ } break;
+
+ case VS::INSTANCE_MULTIMESH: {
+ RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner);
+ RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, true);
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, true);
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, s->attribs[VS::ARRAY_TEX_UV].enabled);
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, s->attribs[VS::ARRAY_TEX_UV2].enabled);
+ } break;
+
+ case VS::INSTANCE_IMMEDIATE: {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_INSTANCING, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_COLOR_INTERP, true);
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV_INTERP, true);
+ state.scene_shader.set_conditional(SceneShaderGLES2::ENABLE_UV2_INTERP, true);
+ } break;
+
+ default: {
+
+ } break;
+ }
+
+ if (storage->config.float_texture_supported) {
+ if (p_skeleton) {
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 1);
+ glBindTexture(GL_TEXTURE_2D, p_skeleton->tex_id);
+ }
+
+ return;
+ }
+
+ if (p_skeleton) {
+ ERR_FAIL_COND(p_skeleton->use_2d);
+
+ PoolVector<float> &transform_buffer = storage->resources.skeleton_transform_cpu_buffer;
+
+ switch (p_element->instance->base_type) {
+ case VS::INSTANCE_MESH: {
+ RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
+
+ if (!s->attribs[VS::ARRAY_BONES].enabled || !s->attribs[VS::ARRAY_WEIGHTS].enabled) {
+ break; // the whole instance has a skeleton, but this surface is not affected by it.
+ }
+
+ // 3 * vec4 per vertex
+ if (transform_buffer.size() < s->array_len * 12) {
+ transform_buffer.resize(s->array_len * 12);
+ }
+
+ const size_t bones_offset = s->attribs[VS::ARRAY_BONES].offset;
+ const size_t bones_stride = s->attribs[VS::ARRAY_BONES].stride;
+ const size_t bone_weight_offset = s->attribs[VS::ARRAY_WEIGHTS].offset;
+ const size_t bone_weight_stride = s->attribs[VS::ARRAY_WEIGHTS].stride;
+
+ {
+ PoolVector<float>::Write write = transform_buffer.write();
+ float *buffer = write.ptr();
+
+ PoolVector<uint8_t>::Read vertex_array_read = s->data.read();
+ const uint8_t *vertex_data = vertex_array_read.ptr();
+
+ for (int i = 0; i < s->array_len; i++) {
+
+ // do magic
+
+ size_t bones[4];
+ float bone_weight[4];
+
+ if (s->attribs[VS::ARRAY_BONES].type == GL_UNSIGNED_BYTE) {
+ // read as byte
+ const uint8_t *bones_ptr = vertex_data + bones_offset + (i * bones_stride);
+ bones[0] = bones_ptr[0];
+ bones[1] = bones_ptr[1];
+ bones[2] = bones_ptr[2];
+ bones[3] = bones_ptr[3];
+ } else {
+ // read as short
+ const uint16_t *bones_ptr = (const uint16_t *)(vertex_data + bones_offset + (i * bones_stride));
+ bones[0] = bones_ptr[0];
+ bones[1] = bones_ptr[1];
+ bones[2] = bones_ptr[2];
+ bones[3] = bones_ptr[3];
+ }
+
+ if (s->attribs[VS::ARRAY_WEIGHTS].type == GL_FLOAT) {
+ // read as float
+ const float *weight_ptr = (const float *)(vertex_data + bone_weight_offset + (i * bone_weight_stride));
+ bone_weight[0] = weight_ptr[0];
+ bone_weight[1] = weight_ptr[1];
+ bone_weight[2] = weight_ptr[2];
+ bone_weight[3] = weight_ptr[3];
+ } else {
+ // read as half
+ const uint16_t *weight_ptr = (const uint16_t *)(vertex_data + bone_weight_offset + (i * bone_weight_stride));
+ bone_weight[0] = (weight_ptr[0] / (float)0xFFFF);
+ bone_weight[1] = (weight_ptr[1] / (float)0xFFFF);
+ bone_weight[2] = (weight_ptr[2] / (float)0xFFFF);
+ bone_weight[3] = (weight_ptr[3] / (float)0xFFFF);
+ }
+
+ size_t offset = i * 12;
+
+ Transform transform;
+
+ Transform bone_transforms[4] = {
+ storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[0]),
+ storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[1]),
+ storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[2]),
+ storage->skeleton_bone_get_transform(p_element->instance->skeleton, bones[3]),
+ };
+
+ transform.origin =
+ bone_weight[0] * bone_transforms[0].origin +
+ bone_weight[1] * bone_transforms[1].origin +
+ bone_weight[2] * bone_transforms[2].origin +
+ bone_weight[3] * bone_transforms[3].origin;
+
+ transform.basis =
+ bone_transforms[0].basis * bone_weight[0] +
+ bone_transforms[1].basis * bone_weight[1] +
+ bone_transforms[2].basis * bone_weight[2] +
+ bone_transforms[3].basis * bone_weight[3];
+
+ float row[3][4] = {
+ { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] },
+ { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] },
+ { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] },
+ };
+
+ size_t transform_buffer_offset = i * 12;
+
+ copymem(&buffer[transform_buffer_offset], row, sizeof(row));
+ }
+ }
+
+ storage->_update_skeleton_transform_buffer(transform_buffer, s->array_len * 12);
+ } break;
+
+ default: {
+
+ } break;
+ }
+ }
+}
+
+void RasterizerSceneGLES2::_render_geometry(RenderList::Element *p_element) {
+
+ switch (p_element->instance->base_type) {
+
+ case VS::INSTANCE_MESH: {
+
+ RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
+
+ // set up
+
+ if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) {
+ glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer);
+
+ glEnableVertexAttribArray(VS::ARRAY_MAX + 0);
+ glEnableVertexAttribArray(VS::ARRAY_MAX + 1);
+ glEnableVertexAttribArray(VS::ARRAY_MAX + 2);
+
+ glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0));
+ glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1));
+ glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2));
+ } else {
+ // just to make sure
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 0);
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 1);
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 2);
+
+ glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0);
+ glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0);
+ glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id);
+
+ if (s->index_array_len > 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id);
+ }
+
+ for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ if (s->attribs[i].enabled) {
+ glEnableVertexAttribArray(i);
+ glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, (uint8_t *)0 + s->attribs[i].offset);
+ } else {
+ glDisableVertexAttribArray(i);
+ }
+ }
+
+ // drawing
+
+ if (s->index_array_len > 0) {
+ glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0);
+ } else {
+ glDrawArrays(gl_primitive[s->primitive], 0, s->array_len);
+ }
+
+ // tear down
+
+ for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ glDisableVertexAttribArray(i);
+ }
+
+ if (s->index_array_len > 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) {
+ glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer);
+
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 0);
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 1);
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 2);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ } break;
+
+ case VS::INSTANCE_MULTIMESH: {
+
+ RasterizerStorageGLES2::MultiMesh *multi_mesh = static_cast<RasterizerStorageGLES2::MultiMesh *>(p_element->owner);
+ RasterizerStorageGLES2::Surface *s = static_cast<RasterizerStorageGLES2::Surface *>(p_element->geometry);
+
+ int amount = MIN(multi_mesh->size, multi_mesh->visible_instances);
+ if (amount == -1) {
+ amount = multi_mesh->size;
+ }
+
+ if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) {
+ glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer);
+
+ glEnableVertexAttribArray(VS::ARRAY_MAX + 0);
+ glEnableVertexAttribArray(VS::ARRAY_MAX + 1);
+ glEnableVertexAttribArray(VS::ARRAY_MAX + 2);
+
+ glVertexAttribPointer(VS::ARRAY_MAX + 0, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 0));
+ glVertexAttribPointer(VS::ARRAY_MAX + 1, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 1));
+ glVertexAttribPointer(VS::ARRAY_MAX + 2, 4, GL_FLOAT, GL_FALSE, sizeof(float) * 12, (const void *)(sizeof(float) * 4 * 2));
+ } else {
+ // just to make sure
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 0);
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 1);
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 2);
+
+ glVertexAttrib4f(VS::ARRAY_MAX + 0, 1, 0, 0, 0);
+ glVertexAttrib4f(VS::ARRAY_MAX + 1, 0, 1, 0, 0);
+ glVertexAttrib4f(VS::ARRAY_MAX + 2, 0, 0, 1, 0);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, s->vertex_id);
+
+ if (s->index_array_len > 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, s->index_id);
+ }
+
+ for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ if (s->attribs[i].enabled) {
+ glEnableVertexAttribArray(i);
+ glVertexAttribPointer(s->attribs[i].index, s->attribs[i].size, s->attribs[i].type, s->attribs[i].normalized, s->attribs[i].stride, (uint8_t *)0 + s->attribs[i].offset);
+ } else {
+ glDisableVertexAttribArray(i);
+ }
+ }
+
+ glDisableVertexAttribArray(12); // transform 0
+ glDisableVertexAttribArray(13); // transform 1
+ glDisableVertexAttribArray(14); // transform 2
+ glDisableVertexAttribArray(15); // color
+ glDisableVertexAttribArray(8); // custom data
+
+ if (!s->attribs[VS::ARRAY_COLOR].enabled) {
+ glDisableVertexAttribArray(VS::ARRAY_COLOR);
+
+ glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+ }
+
+ glVertexAttrib4f(15, 1, 1, 1, 1);
+ glVertexAttrib4f(8, 0, 0, 0, 0);
+
+ int stride = multi_mesh->color_floats + multi_mesh->custom_data_floats + multi_mesh->xform_floats;
+
+ int color_ofs = multi_mesh->xform_floats;
+ int custom_data_ofs = color_ofs + multi_mesh->color_floats;
+
+ // drawing
+
+ for (int i = 0; i < amount; i++) {
+ float *buffer = &multi_mesh->data.write[i * stride];
+
+ {
+ // inline of multimesh_get_transform since it's such a pain
+ // to get a RID from here...
+ Transform transform;
+
+ transform.basis.elements[0][0] = buffer[0];
+ transform.basis.elements[0][1] = buffer[1];
+ transform.basis.elements[0][2] = buffer[2];
+ transform.origin.x = buffer[3];
+ transform.basis.elements[1][0] = buffer[4];
+ transform.basis.elements[1][1] = buffer[5];
+ transform.basis.elements[1][2] = buffer[6];
+ transform.origin.y = buffer[7];
+ transform.basis.elements[2][0] = buffer[8];
+ transform.basis.elements[2][1] = buffer[9];
+ transform.basis.elements[2][2] = buffer[10];
+ transform.origin.z = buffer[11];
+
+ float row[3][4] = {
+ { transform.basis[0][0], transform.basis[0][1], transform.basis[0][2], transform.origin[0] },
+ { transform.basis[1][0], transform.basis[1][1], transform.basis[1][2], transform.origin[1] },
+ { transform.basis[2][0], transform.basis[2][1], transform.basis[2][2], transform.origin[2] },
+ };
+
+ glVertexAttrib4fv(12, row[0]);
+ glVertexAttrib4fv(13, row[1]);
+ glVertexAttrib4fv(14, row[2]);
+ }
+
+ if (multi_mesh->color_floats) {
+ if (multi_mesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ uint8_t *color_data = (uint8_t *)(buffer + color_ofs);
+ glVertexAttrib4f(15, color_data[0] / 255.0, color_data[1] / 255.0, color_data[2] / 255.0, color_data[3] / 255.0);
+ } else {
+ glVertexAttrib4fv(15, buffer + color_ofs);
+ }
+ }
+
+ if (multi_mesh->custom_data_floats) {
+ glVertexAttrib4fv(8, buffer + custom_data_ofs);
+ }
+
+ if (s->index_array_len > 0) {
+ glDrawElements(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0);
+ } else {
+ glDrawArrays(gl_primitive[s->primitive], 0, s->array_len);
+ }
+ }
+
+ // tear down
+
+ for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ glDisableVertexAttribArray(i);
+ }
+
+ if (s->index_array_len > 0) {
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ if (p_element->instance->skeleton.is_valid() && s->attribs[VS::ARRAY_BONES].enabled && s->attribs[VS::ARRAY_WEIGHTS].enabled) {
+ glBindBuffer(GL_ARRAY_BUFFER, storage->resources.skeleton_transform_buffer);
+
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 0);
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 1);
+ glDisableVertexAttribArray(VS::ARRAY_MAX + 2);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ } break;
+
+ case VS::INSTANCE_IMMEDIATE: {
+ const RasterizerStorageGLES2::Immediate *im = static_cast<const RasterizerStorageGLES2::Immediate *>(p_element->geometry);
+
+ if (im->building) {
+ return;
+ }
+
+ bool restore_tex = false;
+
+ glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer);
+
+ for (const List<RasterizerStorageGLES2::Immediate::Chunk>::Element *E = im->chunks.front(); E; E = E->next()) {
+ const RasterizerStorageGLES2::Immediate::Chunk &c = E->get();
+
+ if (c.vertices.empty()) {
+ continue;
+ }
+
+ int vertices = c.vertices.size();
+
+ uint32_t buf_ofs = 0;
+
+ storage->info.render.vertices_count += vertices;
+
+ if (c.texture.is_valid() && storage->texture_owner.owns(c.texture)) {
+ RasterizerStorageGLES2::Texture *t = storage->texture_owner.get(c.texture);
+
+ t = t->get_ptr();
+
+ if (t->redraw_if_visible) {
+ VisualServerRaster::redraw_request();
+ }
+
+#ifdef TOOLS_ENABLED
+ if (t->detect_3d) {
+ t->detect_3d(t->detect_3d_ud);
+ }
+#endif
+ if (t->render_target) {
+ t->render_target->used_in_frame = true;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(t->target, t->tex_id);
+ restore_tex = true;
+ } else if (restore_tex) {
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, state.current_main_tex);
+ restore_tex = false;
+ }
+
+ if (!c.normals.empty()) {
+ glEnableVertexAttribArray(VS::ARRAY_NORMAL);
+ glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.normals.ptr());
+ glVertexAttribPointer(VS::ARRAY_NORMAL, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), ((uint8_t *)NULL) + buf_ofs);
+ buf_ofs += sizeof(Vector3) * vertices;
+ } else {
+ glDisableVertexAttribArray(VS::ARRAY_NORMAL);
+ }
+
+ if (!c.tangents.empty()) {
+ glEnableVertexAttribArray(VS::ARRAY_TANGENT);
+ glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Plane) * vertices, c.tangents.ptr());
+ glVertexAttribPointer(VS::ARRAY_TANGENT, 4, GL_FLOAT, GL_FALSE, sizeof(Plane), ((uint8_t *)NULL) + buf_ofs);
+ buf_ofs += sizeof(Plane) * vertices;
+ } else {
+ glDisableVertexAttribArray(VS::ARRAY_TANGENT);
+ }
+
+ if (!c.colors.empty()) {
+ glEnableVertexAttribArray(VS::ARRAY_COLOR);
+ glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Color) * vertices, c.colors.ptr());
+ glVertexAttribPointer(VS::ARRAY_COLOR, 4, GL_FLOAT, GL_FALSE, sizeof(Color), ((uint8_t *)NULL) + buf_ofs);
+ buf_ofs += sizeof(Color) * vertices;
+ } else {
+ glDisableVertexAttribArray(VS::ARRAY_COLOR);
+ }
+
+ if (!c.uvs.empty()) {
+ glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uvs.ptr());
+ glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)NULL) + buf_ofs);
+ buf_ofs += sizeof(Vector2) * vertices;
+ } else {
+ glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ }
+
+ if (!c.uv2s.empty()) {
+ glEnableVertexAttribArray(VS::ARRAY_TEX_UV2);
+ glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector2) * vertices, c.uv2s.ptr());
+ glVertexAttribPointer(VS::ARRAY_TEX_UV2, 2, GL_FLOAT, GL_FALSE, sizeof(Vector2), ((uint8_t *)NULL) + buf_ofs);
+ buf_ofs += sizeof(Vector2) * vertices;
+ } else {
+ glDisableVertexAttribArray(VS::ARRAY_TEX_UV2);
+ }
+
+ glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+ glBufferSubData(GL_ARRAY_BUFFER, buf_ofs, sizeof(Vector3) * vertices, c.vertices.ptr());
+ glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3), ((uint8_t *)NULL) + buf_ofs);
+
+ glDrawArrays(gl_primitive[c.primitive], 0, c.vertices.size());
+ }
+
+ if (restore_tex) {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, state.current_main_tex);
+ restore_tex = false;
+ }
+
+ } break;
+ }
+}
+
+void RasterizerSceneGLES2::_render_render_list(RenderList::Element **p_elements, int p_element_count, const RID *p_directional_lights, int p_directional_light_count, const Transform &p_view_transform, const CameraMatrix &p_projection, RID p_shadow_atlas, Environment *p_env, GLuint p_base_env, float p_shadow_bias, float p_shadow_normal_bias, bool p_reverse_cull, bool p_alpha_pass, bool p_shadow, bool p_directional_add) {
+
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+
+ 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;
+
+ bool use_radiance_map = false;
+
+ VMap<RID, Vector<RenderList::Element *> > lit_objects;
+
+ for (int i = 0; i < p_element_count; i++) {
+ RenderList::Element *e = p_elements[i];
+
+ RasterizerStorageGLES2::Material *material = e->material;
+
+ RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton);
+
+ if (p_base_env) {
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 2);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, p_base_env);
+ use_radiance_map = true;
+ }
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map);
+
+ if (material->shader->spatial.unshaded) {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false);
+ } else {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, use_radiance_map);
+ }
+
+ // opaque pass
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, false);
+
+ _setup_geometry(e, skeleton);
+
+ _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
+
+ if (use_radiance_map) {
+ state.scene_shader.set_uniform(SceneShaderGLES2::RADIANCE_INVERSE_XFORM, p_view_transform);
+ }
+
+ if (p_shadow) {
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_BIAS, p_shadow_bias);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_NORMAL_BIAS, p_shadow_normal_bias);
+ }
+
+ if (p_env) {
+ state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, p_env->bg_energy);
+ state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, p_env->ambient_sky_contribution);
+ state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, p_env->ambient_color);
+ state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, p_env->ambient_energy);
+
+ } else {
+ state.scene_shader.set_uniform(SceneShaderGLES2::BG_ENERGY, 1.0);
+ state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_SKY_CONTRIBUTION, 1.0);
+ state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_COLOR, Color(1.0, 1.0, 1.0, 1.0));
+ state.scene_shader.set_uniform(SceneShaderGLES2::AMBIENT_ENERGY, 1.0);
+ }
+
+ glEnable(GL_BLEND);
+
+ if (p_alpha_pass || p_directional_add) {
+ int desired_blend_mode;
+ if (p_directional_add) {
+ desired_blend_mode = RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD;
+ } else {
+ desired_blend_mode = material->shader->spatial.blend_mode;
+ }
+
+ switch (desired_blend_mode) {
+
+ case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MIX: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+
+ } break;
+ case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_ADD: {
+
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(p_alpha_pass ? GL_SRC_ALPHA : GL_ONE, GL_ONE);
+
+ } break;
+ case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_SUB: {
+
+ glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+ } break;
+ case RasterizerStorageGLES2::Shader::Spatial::BLEND_MODE_MUL: {
+ glBlendEquation(GL_FUNC_ADD);
+ if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+ glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_DST_ALPHA, GL_ZERO);
+ } else {
+ glBlendFuncSeparate(GL_DST_COLOR, GL_ZERO, GL_ZERO, GL_ONE);
+ }
+
+ } break;
+ }
+ } else {
+ // no blend mode given - assume mix
+ glBlendEquation(GL_FUNC_ADD);
+ if (storage->frame.current_rt && storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT]) {
+ glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+ } else {
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+ }
+ }
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse());
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse());
+
+ 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?
+ state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
+
+ _render_geometry(e);
+
+ if (material->shader->spatial.unshaded)
+ continue;
+
+ if (p_shadow)
+ continue;
+
+ for (int light = 0; light < e->instance->light_instances.size(); light++) {
+
+ RID light_instance = e->instance->light_instances[light];
+
+ lit_objects[light_instance].push_back(e);
+ }
+ }
+
+ if (p_shadow) {
+ state.scene_shader.set_conditional(SceneShaderGLES2::USE_RADIANCE_MAP, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, false);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, false);
+ return;
+ }
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, true);
+
+ glEnable(GL_BLEND);
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE);
+
+ for (int lo = 0; lo < lit_objects.size(); lo++) {
+
+ RID key = lit_objects.getk(lo);
+
+ LightInstance *light = light_instance_owner.getornull(key);
+ RasterizerStorageGLES2::Light *light_ptr = light->light_ptr;
+
+ const Vector<RenderList::Element *> &list = lit_objects.getv(lo);
+
+ for (int i = 0; i < list.size(); i++) {
+
+ RenderList::Element *e = list[i];
+ RasterizerStorageGLES2::Material *material = e->material;
+
+ RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton);
+
+ {
+ _setup_geometry(e, skeleton);
+
+ _setup_material(material, p_reverse_cull, p_alpha_pass, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
+ if (shadow_atlas != NULL) {
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4);
+ glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
+ }
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse());
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse());
+
+ 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?
+ state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
+ }
+
+ switch (light_ptr->type) {
+ case VS::LIGHT_OMNI: {
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)1);
+
+ Vector3 position = p_view_transform.inverse().xform(light->transform.origin);
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position);
+
+ 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];
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation);
+
+ if (light_ptr->shadow && shadow_atlas->shadow_owners.has(light->self)) {
+
+ uint32_t key = shadow_atlas->shadow_owners[light->self];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size());
+
+ uint32_t atlas_size = shadow_atlas->size;
+ uint32_t quadrant_size = atlas_size >> 1;
+
+ uint32_t x = (quadrant & 1) * quadrant_size;
+ uint32_t y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ uint32_t width = shadow_size;
+ uint32_t height = shadow_size;
+
+ if (light->light_ptr->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
+ height /= 2;
+ } else {
+ width /= 2;
+ }
+
+ Transform proj = (p_view_transform.inverse() * light->transform).inverse();
+
+ Color light_clamp;
+ light_clamp[0] = float(x) / atlas_size;
+ light_clamp[1] = float(y) / atlas_size;
+ light_clamp[2] = float(width) / atlas_size;
+ light_clamp[3] = float(height) / atlas_size;
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, proj);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp);
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0);
+ } else {
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0);
+ }
+ } break;
+
+ case VS::LIGHT_SPOT: {
+ Vector3 position = p_view_transform.inverse().xform(light->transform.origin);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)2);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_POSITION, position);
+
+ Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized();
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction);
+ Color attenuation = Color(0.0, 0.0, 0.0, 0.0);
+ attenuation.a = light_ptr->param[VS::LIGHT_PARAM_ATTENUATION];
+ float range = light_ptr->param[VS::LIGHT_PARAM_RANGE];
+ float spot_attenuation = light_ptr->param[VS::LIGHT_PARAM_SPOT_ATTENUATION];
+ float angle = light_ptr->param[VS::LIGHT_PARAM_SPOT_ANGLE];
+ angle = Math::cos(Math::deg2rad(angle));
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ATTENUATION, attenuation);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ATTENUATION, spot_attenuation);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_RANGE, spot_attenuation);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPOT_ANGLE, angle);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_RANGE, range);
+
+ if (light->light_ptr->shadow && shadow_atlas && shadow_atlas->shadow_owners.has(light->self)) {
+ uint32_t key = shadow_atlas->shadow_owners[light->self];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_CONTINUE(shadow >= (uint32_t)shadow_atlas->quadrants[quadrant].shadows.size());
+
+ uint32_t atlas_size = shadow_atlas->size;
+ uint32_t quadrant_size = atlas_size >> 1;
+
+ uint32_t x = (quadrant & 1) * quadrant_size;
+ uint32_t y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ uint32_t width = shadow_size;
+ uint32_t height = shadow_size;
+
+ Rect2 rect(float(x) / atlas_size, float(y) / atlas_size, float(width) / atlas_size, float(height) / atlas_size);
+
+ Color light_clamp;
+ light_clamp[0] = rect.position.x;
+ light_clamp[1] = rect.position.y;
+ light_clamp[2] = rect.size.x;
+ light_clamp[3] = rect.size.y;
+
+ Transform modelview = (p_view_transform.inverse() * light->transform).inverse();
+
+ CameraMatrix bias;
+ bias.set_light_bias();
+
+ CameraMatrix rectm;
+ rectm.set_light_atlas_rect(rect);
+
+ CameraMatrix shadow_matrix = rectm * bias * light->shadow_transform[0].camera * modelview;
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX, shadow_matrix);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp);
+
+ } else {
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0);
+ }
+
+ } break;
+
+ default: break;
+ }
+
+ float energy = light->light_ptr->param[VS::LIGHT_PARAM_ENERGY];
+ float specular = light->light_ptr->param[VS::LIGHT_PARAM_SPECULAR];
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ENERGY, energy);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, light->light_ptr->color.to_linear());
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular);
+
+ _render_geometry(e);
+ }
+ }
+
+ for (int dl = 0; dl < p_directional_light_count; dl++) {
+ RID light_rid = p_directional_lights[dl];
+ LightInstance *light = light_instance_owner.getornull(light_rid);
+ RasterizerStorageGLES2::Light *light_ptr = light->light_ptr;
+
+ switch (light_ptr->directional_shadow_mode) {
+ case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
+ } break;
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM2, true);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits);
+ } break;
+
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM4, true);
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_USE_PSSM_BLEND, light_ptr->directional_blend_splits);
+ } break;
+ default:
+ break;
+ }
+
+ for (int i = 0; i < p_element_count; i++) {
+
+ RenderList::Element *e = p_elements[i];
+ RasterizerStorageGLES2::Material *material = e->material;
+ RasterizerStorageGLES2::Skeleton *skeleton = storage->skeleton_owner.getornull(e->instance->skeleton);
+
+ {
+ _setup_material(material, p_reverse_cull, false, Size2i(skeleton ? skeleton->size * 3 : 0, 0));
+
+ if (directional_shadow.depth) {
+ glActiveTexture(GL_TEXTURE0 + storage->config.max_texture_image_units - 4); // TODO move into base pass
+ glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
+ }
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_MATRIX, p_view_transform.inverse());
+ state.scene_shader.set_uniform(SceneShaderGLES2::CAMERA_INVERSE_MATRIX, p_view_transform);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_MATRIX, p_projection);
+ state.scene_shader.set_uniform(SceneShaderGLES2::PROJECTION_INVERSE_MATRIX, p_projection.inverse());
+
+ 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?
+ state.scene_shader.set_uniform(SceneShaderGLES2::WORLD_TRANSFORM, e->instance->transform);
+ }
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_TYPE, (int)0);
+ Vector3 direction = p_view_transform.inverse().basis.xform(light->transform.basis.xform(Vector3(0, 0, -1))).normalized();
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_DIRECTION, direction);
+
+ float energy = light_ptr->param[VS::LIGHT_PARAM_ENERGY];
+ float specular = light_ptr->param[VS::LIGHT_PARAM_SPECULAR];
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_ENERGY, energy);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPECULAR, specular);
+
+ float sign = light_ptr->negative ? -1 : 1;
+
+ Color linear_col = light_ptr->color.to_linear();
+ Color color;
+ for (int c = 0; c < 3; c++)
+ color[c] = linear_col[c] * sign * energy * Math_PI;
+
+ color[3] = 0;
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_COLOR, color);
+
+ CameraMatrix matrices[4];
+
+ if (light_ptr->shadow && directional_shadow.depth) {
+
+ int shadow_count = 0;
+ Color split_offsets;
+
+ switch (light_ptr->directional_shadow_mode) {
+ case VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL: {
+ shadow_count = 1;
+ } break;
+
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS: {
+ shadow_count = 2;
+ } break;
+
+ case VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS: {
+ shadow_count = 4;
+ } break;
+ }
+
+ for (int k = 0; k < shadow_count; k++) {
+
+ uint32_t x = light->directional_rect.position.x;
+ uint32_t y = light->directional_rect.position.y;
+ uint32_t width = light->directional_rect.size.x;
+ uint32_t height = light->directional_rect.size.y;
+
+ if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+
+ width /= 2;
+ height /= 2;
+
+ if (k == 0) {
+
+ } else if (k == 1) {
+ x += width;
+ } else if (k == 2) {
+ y += height;
+ } else if (k == 3) {
+ x += width;
+ y += height;
+ }
+
+ } else if (light_ptr->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+
+ height /= 2;
+
+ if (k == 0) {
+
+ } else {
+ y += height;
+ }
+ }
+
+ split_offsets[k] = light->shadow_transform[k].split;
+
+ Transform modelview = (p_view_transform * light->shadow_transform[k].transform).inverse();
+
+ CameraMatrix bias;
+ bias.set_light_bias();
+ CameraMatrix rectm;
+ Rect2 atlas_rect = Rect2(float(x) / directional_shadow.size, float(y) / directional_shadow.size, float(width) / directional_shadow.size, float(height) / directional_shadow.size);
+ rectm.set_light_atlas_rect(atlas_rect);
+
+ CameraMatrix shadow_mtx = rectm * bias * light->shadow_transform[k].camera * modelview;
+ matrices[k] = shadow_mtx.inverse();
+
+ Color light_clamp;
+ light_clamp[0] = atlas_rect.position.x;
+ light_clamp[1] = atlas_rect.position.y;
+ light_clamp[2] = atlas_rect.size.x;
+ light_clamp[3] = atlas_rect.size.y;
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 1.0);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_CLAMP, light_clamp);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SPLIT_OFFSETS, split_offsets);
+ }
+
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX1, matrices[0]);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX2, matrices[1]);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX3, matrices[2]);
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_SHADOW_MATRIX4, matrices[3]);
+ } else {
+ state.scene_shader.set_uniform(SceneShaderGLES2::LIGHT_HAS_SHADOW, 0.0);
+ }
+
+ _render_geometry(e);
+ }
+ }
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::LIGHT_PASS, 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);
+}
+
+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) {
+ ERR_FAIL_COND(!p_sky);
+
+ RasterizerStorageGLES2::Texture *tex = storage->texture_owner.getornull(p_sky->panorama);
+ ERR_FAIL_COND(!tex);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(tex->target, tex->tex_id);
+
+ glDepthMask(GL_TRUE);
+ glEnable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL);
+ glColorMask(1, 1, 1, 1);
+
+ // Camera
+ CameraMatrix camera;
+
+ if (p_custom_fov) {
+
+ float near_plane = p_projection.get_z_near();
+ float far_plane = p_projection.get_z_far();
+ float aspect = p_projection.get_aspect();
+
+ camera.set_perspective(p_custom_fov, aspect, near_plane, far_plane);
+ } else {
+ camera = p_projection;
+ }
+
+ float flip_sign = p_vflip ? -1 : 1;
+
+ // If matrix[2][0] or matrix[2][1] we're dealing with an asymmetrical projection matrix. This is the case for stereoscopic rendering (i.e. VR).
+ // To ensure the image rendered is perspective correct we need to move some logic into the shader. For this the USE_ASYM_PANO option is introduced.
+ // It also means the uv coordinates are ignored in this mode and we don't need our loop.
+ bool asymmetrical = ((camera.matrix[2][0] != 0.0) || (camera.matrix[2][1] != 0.0));
+
+ Vector3 vertices[8] = {
+ Vector3(-1, -1 * flip_sign, 1),
+ Vector3(0, 1, 0),
+ Vector3(1, -1 * flip_sign, 1),
+ Vector3(1, 1, 0),
+ Vector3(1, 1 * flip_sign, 1),
+ Vector3(1, 0, 0),
+ Vector3(-1, 1 * flip_sign, 1),
+ Vector3(0, 0, 0),
+ };
+
+ if (!asymmetrical) {
+ float vw, vh, zn;
+ camera.get_viewport_size(vw, vh);
+ zn = p_projection.get_z_near();
+
+ for (int i = 0; i < 4; i++) {
+ Vector3 uv = vertices[i * 2 + 1];
+ uv.x = (uv.x * 2.0 - 1.0) * vw;
+ uv.y = -(uv.y * 2.0 - 1.0) * vh;
+ uv.z = -zn;
+ vertices[i * 2 + 1] = p_transform.basis.xform(uv).normalized();
+ vertices[i * 2 + 1].z = -vertices[i * 2 + 1].z;
+ }
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts);
+ glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(Vector3) * 8, vertices);
+
+ // bind sky vertex array....
+ glVertexAttribPointer(VS::ARRAY_VERTEX, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, 0);
+ glVertexAttribPointer(VS::ARRAY_TEX_UV, 3, GL_FLOAT, GL_FALSE, sizeof(Vector3) * 2, ((uint8_t *)NULL) + sizeof(Vector3));
+ glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+ glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+
+ 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);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+
+ glDisableVertexAttribArray(VS::ARRAY_VERTEX);
+ glDisableVertexAttribArray(VS::ARRAY_TEX_UV);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false);
+}
+
void RasterizerSceneGLES2::render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass) {
+
+ glEnable(GL_BLEND);
+
+ GLuint current_fb = storage->frame.current_rt->fbo;
+ Environment *env = environment_owner.getornull(p_environment);
+
+ // render list stuff
+
+ render_list.clear();
+ _fill_render_list(p_cull_result, p_cull_count, false, false);
+
+ // other stuff
+
+ glBindFramebuffer(GL_FRAMEBUFFER, current_fb);
+
+ glDepthFunc(GL_LEQUAL);
+ glDepthMask(GL_TRUE);
+ glClearDepth(1.0f);
+ glEnable(GL_DEPTH_TEST);
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ storage->frame.clear_request = false;
+
+ glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1);
+
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ // render sky
+ RasterizerStorageGLES2::Sky *sky = NULL;
+ GLuint env_radiance_tex = 0;
+ if (env) {
+ switch (env->bg_mode) {
+
+ case VS::ENV_BG_COLOR_SKY:
+ case VS::ENV_BG_SKY: {
+ sky = storage->sky_owner.getornull(env->sky);
+
+ if (sky) {
+ env_radiance_tex = sky->radiance;
+ }
+ } break;
+
+ default: {
+ // FIXME: implement other background modes
+ } break;
+ }
+ }
+
+ if (env && env->bg_mode == VS::ENV_BG_SKY && (!storage->frame.current_rt || !storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_TRANSPARENT])) {
+
+ if (sky && sky->panorama.is_valid()) {
+ _draw_sky(sky, p_cam_projection, p_cam_transform, false, env->sky_custom_fov, env->bg_energy);
+ }
+ }
+
+ Vector<RID> directional_lights;
+
+ for (int i = 0; i < p_light_cull_count; i++) {
+ RID light_rid = p_light_cull_result[i];
+
+ LightInstance *light = light_instance_owner.getornull(light_rid);
+
+ if (light->light_ptr->type == VS::LIGHT_DIRECTIONAL) {
+ directional_lights.push_back(light_rid);
+ }
+ }
+
+ // render opaque things first
+ render_list.sort_by_key(false);
+ _render_render_list(render_list.elements, render_list.element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, false, false, false);
+
+ // alpha pass
+
+ glBlendEquation(GL_FUNC_ADD);
+ glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
+
+ render_list.sort_by_key(true);
+ _render_render_list(&render_list.elements[render_list.max_elements - render_list.alpha_element_count], render_list.alpha_element_count, directional_lights.ptr(), directional_lights.size(), p_cam_transform, p_cam_projection, p_shadow_atlas, env, env_radiance_tex, 0.0, 0.0, false, true, false, false);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+
+ // #define GLES2_SHADOW_ATLAS_DEBUG_VIEW
+
+#ifdef GLES2_SHADOW_ATLAS_DEBUG_VIEW
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+ if (shadow_atlas) {
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, shadow_atlas->depth);
+
+ glViewport(0, 0, storage->frame.current_rt->width / 4, storage->frame.current_rt->height / 4);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUBEMAP, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_COPY_SECTION, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_CUSTOM_ALPHA, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_MULTIPLIER, false);
+ storage->shaders.copy.set_conditional(CopyShaderGLES2::USE_PANORAMA, false);
+ storage->shaders.copy.bind();
+
+ storage->_copy_screen();
+ }
+#endif
}
void RasterizerSceneGLES2::render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count) {
+
+ LightInstance *light_instance = light_instance_owner.getornull(p_light);
+ ERR_FAIL_COND(!light_instance);
+
+ RasterizerStorageGLES2::Light *light = light_instance->light_ptr;
+ ERR_FAIL_COND(!light);
+
+ uint32_t x;
+ uint32_t y;
+ uint32_t width;
+ uint32_t height;
+ uint32_t vp_height;
+
+ float zfar = 0;
+ bool flip_facing = false;
+ int custom_vp_size = 0;
+
+ GLuint fbo = 0;
+
+ int current_cubemap = -1;
+ float bias = 0;
+ float normal_bias = 0;
+
+ CameraMatrix light_projection;
+ Transform light_transform;
+
+ // TODO directional light
+
+ if (light->type == VS::LIGHT_DIRECTIONAL) {
+ // set pssm stuff
+
+ // TODO set this only when changed
+
+ light_instance->light_directional_index = directional_shadow.current_light;
+ light_instance->last_scene_shadow_pass = scene_pass;
+
+ directional_shadow.current_light++;
+
+ if (directional_shadow.light_count == 1) {
+ light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size);
+ } else if (directional_shadow.light_count == 2) {
+ light_instance->directional_rect = Rect2(0, 0, directional_shadow.size, directional_shadow.size / 2);
+ if (light_instance->light_directional_index == 1) {
+ light_instance->directional_rect.position.x += light_instance->directional_rect.size.x;
+ }
+ } else { //3 and 4
+ light_instance->directional_rect = Rect2(0, 0, directional_shadow.size / 2, directional_shadow.size / 2);
+ if (light_instance->light_directional_index & 1) {
+ light_instance->directional_rect.position.x += light_instance->directional_rect.size.x;
+ }
+ if (light_instance->light_directional_index / 2) {
+ light_instance->directional_rect.position.y += light_instance->directional_rect.size.y;
+ }
+ }
+
+ light_projection = light_instance->shadow_transform[p_pass].camera;
+ light_transform = light_instance->shadow_transform[p_pass].transform;
+
+ x = light_instance->directional_rect.position.x;
+ y = light_instance->directional_rect.position.y;
+ width = light_instance->directional_rect.size.width;
+ height = light_instance->directional_rect.size.height;
+
+ if (light->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_4_SPLITS) {
+
+ width /= 2;
+ height /= 2;
+
+ if (p_pass == 0) {
+
+ } else if (p_pass == 1) {
+ x += width;
+ } else if (p_pass == 2) {
+ y += height;
+ } else if (p_pass == 3) {
+ x += width;
+ y += height;
+ }
+
+ } else if (light->directional_shadow_mode == VS::LIGHT_DIRECTIONAL_SHADOW_PARALLEL_2_SPLITS) {
+
+ height /= 2;
+
+ if (p_pass == 0) {
+
+ } else {
+ y += height;
+ }
+ }
+
+ float bias_mult = Math::lerp(1.0f, light_instance->shadow_transform[p_pass].bias_scale, light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE]);
+ zfar = light->param[VS::LIGHT_PARAM_RANGE];
+ bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS] * bias_mult;
+ 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];
+
+ uint32_t quadrant = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x03;
+ uint32_t shadow = key & ShadowAtlas::SHADOW_INDEX_MASK;
+
+ ERR_FAIL_INDEX((int)shadow, shadow_atlas->quadrants[quadrant].shadows.size());
+
+ uint32_t quadrant_size = shadow_atlas->size >> 1;
+
+ x = (quadrant & 1) * quadrant_size;
+ y = (quadrant >> 1) * quadrant_size;
+
+ uint32_t shadow_size = (quadrant_size / shadow_atlas->quadrants[quadrant].subdivision);
+ x += (shadow % shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+ y += (shadow / shadow_atlas->quadrants[quadrant].subdivision) * shadow_size;
+
+ width = shadow_size;
+ height = shadow_size;
+
+ if (light->type == VS::LIGHT_OMNI) {
+ // cubemap only
+ if (light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE) {
+ int cubemap_index = shadow_cubemaps.size() - 1;
+
+ // find an appropriate cubemap to render to
+ for (int i = shadow_cubemaps.size() - 1; i >= 0; i--) {
+ if (shadow_cubemaps[i].size > shadow_size * 2) {
+ break;
+ }
+
+ cubemap_index = i;
+ }
+
+ fbo = shadow_cubemaps[cubemap_index].fbo[p_pass];
+ light_projection = light_instance->shadow_transform[0].camera;
+ light_transform = light_instance->shadow_transform[0].transform;
+
+ custom_vp_size = shadow_cubemaps[cubemap_index].size;
+ zfar = light->param[VS::LIGHT_PARAM_RANGE];
+
+ current_cubemap = cubemap_index;
+ }
+ } else {
+ light_projection = light_instance->shadow_transform[0].camera;
+ light_transform = light_instance->shadow_transform[0].transform;
+
+ flip_facing = false;
+ zfar = light->param[VS::LIGHT_PARAM_RANGE];
+ bias = light->param[VS::LIGHT_PARAM_SHADOW_BIAS];
+ normal_bias = light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS];
+ }
+ }
+
+ render_list.clear();
+
+ _fill_render_list(p_cull_result, p_cull_count, true, true);
+
+ render_list.sort_by_depth(false);
+
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glEnable(GL_DEPTH_TEST);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, fbo);
+
+ glDepthMask(GL_TRUE);
+ glColorMask(0, 0, 0, 0);
+
+ if (custom_vp_size) {
+ glViewport(0, 0, custom_vp_size, custom_vp_size);
+ glScissor(0, 0, custom_vp_size, custom_vp_size);
+ } else {
+ glViewport(x, y, width, height);
+ glScissor(x, y, width, height);
+ }
+
+ glEnable(GL_SCISSOR_TEST);
+ glClearDepth(1.0f);
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glDisable(GL_SCISSOR_TEST);
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, true);
+
+ _render_render_list(render_list.elements, render_list.element_count, NULL, 0, light_transform, light_projection, RID(), NULL, 0, bias, normal_bias, false, false, true, false);
+
+ state.scene_shader.set_conditional(SceneShaderGLES2::RENDER_DEPTH, false);
+
+ // convert cubemap to dual paraboloid if needed
+ if (light->type == VS::LIGHT_OMNI && light->omni_shadow_mode == VS::LIGHT_OMNI_SHADOW_CUBE && p_pass == 5) {
+ ShadowAtlas *shadow_atlas = shadow_atlas_owner.getornull(p_shadow_atlas);
+
+ glBindFramebuffer(GL_FRAMEBUFFER, shadow_atlas->fbo);
+ state.cube_to_dp_shader.bind();
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, shadow_cubemaps[current_cubemap].cubemap);
+
+ glDisable(GL_CULL_FACE);
+
+ for (int i = 0; i < 2; i++) {
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_FLIP, i == 1);
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_NEAR, light_projection.get_z_near());
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::Z_FAR, light_projection.get_z_far());
+ state.cube_to_dp_shader.set_uniform(CubeToDpShaderGLES2::BIAS, light->param[VS::LIGHT_PARAM_SHADOW_BIAS]);
+
+ uint32_t local_width = width;
+ uint32_t local_height = height;
+ uint32_t local_x = x;
+ uint32_t local_y = y;
+
+ if (light->omni_shadow_detail == VS::LIGHT_OMNI_SHADOW_DETAIL_HORIZONTAL) {
+ local_height /= 2;
+ local_y += i * local_height;
+ } else {
+ local_width /= 2;
+ local_x += i * local_width;
+ }
+
+ glViewport(local_x, local_y, local_width, local_height);
+ glScissor(local_x, local_y, local_width, local_height);
+
+ glEnable(GL_SCISSOR_TEST);
+
+ glClearDepth(1.0f);
+
+ glClear(GL_DEPTH_BUFFER_BIT);
+ glDisable(GL_SCISSOR_TEST);
+
+ glDisable(GL_BLEND);
+
+ storage->_copy_screen();
+ }
+ }
+
+ glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
}
void RasterizerSceneGLES2::set_scene_pass(uint64_t p_pass) {
+ scene_pass = p_pass;
}
bool RasterizerSceneGLES2::free(RID p_rid) {
@@ -223,6 +2371,109 @@ void RasterizerSceneGLES2::set_debug_draw_mode(VS::ViewportDebugDraw p_debug_dra
}
void RasterizerSceneGLES2::initialize() {
+ state.scene_shader.init();
+ state.cube_to_dp_shader.init();
+
+ render_list.init();
+
+ shadow_atlas_realloc_tolerance_msec = 500;
+
+ {
+ //default material and shader
+
+ default_shader = storage->shader_create();
+ storage->shader_set_code(default_shader, "shader_type spatial;\n");
+ default_material = storage->material_create();
+ storage->material_set_shader(default_material, default_shader);
+
+ default_shader_twosided = storage->shader_create();
+ default_material_twosided = storage->material_create();
+ storage->shader_set_code(default_shader_twosided, "shader_type spatial; render_mode cull_disabled;\n");
+ storage->material_set_shader(default_material_twosided, default_shader_twosided);
+ }
+
+ {
+ glGenBuffers(1, &state.sky_verts);
+ glBindBuffer(GL_ARRAY_BUFFER, state.sky_verts);
+ glBufferData(GL_ARRAY_BUFFER, sizeof(Vector3) * 8, NULL, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ {
+ uint32_t immediate_buffer_size = GLOBAL_DEF("rendering/limits/buffers/immediate_buffer_size_kb", 2048);
+
+ glGenBuffers(1, &state.immediate_buffer);
+ glBindBuffer(GL_ARRAY_BUFFER, state.immediate_buffer);
+ glBufferData(GL_ARRAY_BUFFER, immediate_buffer_size * 1024, NULL, GL_DYNAMIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
+
+ // cubemaps for shadows
+ {
+ int max_shadow_cubemap_sampler_size = 512;
+
+ int cube_size = max_shadow_cubemap_sampler_size;
+
+ glActiveTexture(GL_TEXTURE0);
+
+ while (cube_size >= 32) {
+
+ ShadowCubeMap cube;
+
+ cube.size = cube_size;
+
+ glGenTextures(1, &cube.cubemap);
+ 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);
+ }
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glGenFramebuffers(6, cube.fbo);
+ for (int i = 0; i < 6; i++) {
+
+ glBindFramebuffer(GL_FRAMEBUFFER, cube.fbo[i]);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, _cube_side_enum[i], cube.cubemap, 0);
+ }
+
+ shadow_cubemaps.push_back(cube);
+
+ cube_size >>= 1;
+ }
+ }
+
+ {
+ // directional shadows
+
+ directional_shadow.light_count = 0;
+ directional_shadow.size = next_power_of_2(GLOBAL_GET("rendering/quality/directional_shadow/size"));
+
+ glGenFramebuffers(1, &directional_shadow.fbo);
+ glBindFramebuffer(GL_FRAMEBUFFER, directional_shadow.fbo);
+
+ glGenTextures(1, &directional_shadow.depth);
+ glBindTexture(GL_TEXTURE_2D, directional_shadow.depth);
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, directional_shadow.size, directional_shadow.size, 0, GL_DEPTH_COMPONENT, GL_UNSIGNED_INT, NULL);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, directional_shadow.depth, 0);
+
+ GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ ERR_PRINT("Directional shadow framebuffer status invalid");
+ }
+ }
}
void RasterizerSceneGLES2::iteration() {
diff --git a/drivers/gles2/rasterizer_scene_gles2.h b/drivers/gles2/rasterizer_scene_gles2.h
index 99f034afed..72dbe14387 100644
--- a/drivers/gles2/rasterizer_scene_gles2.h
+++ b/drivers/gles2/rasterizer_scene_gles2.h
@@ -33,10 +33,10 @@
/* Must come before shaders or the Windows build fails... */
#include "rasterizer_storage_gles2.h"
+#include "shaders/cube_to_dp.glsl.gen.h"
#include "shaders/scene.glsl.gen.h"
/*
-#include "drivers/gles3/shaders/cube_to_dp.glsl.gen.h"
#include "drivers/gles3/shaders/effect_blur.glsl.gen.h"
#include "drivers/gles3/shaders/exposure.glsl.gen.h"
#include "drivers/gles3/shaders/resolve.glsl.gen.h"
@@ -52,6 +52,13 @@
class RasterizerSceneGLES2 : public RasterizerScene {
public:
+ RID default_material;
+ RID default_material_twosided;
+ RID default_shader;
+ RID default_shader_twosided;
+
+ uint64_t scene_pass;
+
RasterizerStorageGLES2 *storage;
struct State {
@@ -63,7 +70,12 @@ public:
GLuint current_main_tex;
SceneShaderGLES2 scene_shader;
- // CubeToDpShaderGLES3 cube_to_dp_shader;
+ CubeToDpShaderGLES2 cube_to_dp_shader;
+
+ GLuint sky_verts;
+
+ GLuint immediate_buffer;
+
// ResolveShaderGLES3 resolve_shader;
// ScreenSpaceReflectionShaderGLES3 ssr_shader;
// EffectBlurShaderGLES3 effect_blur_shader;
@@ -128,7 +140,6 @@ public:
GLuint env_radiance_ubo;
- GLuint sky_verts;
GLuint sky_array;
GLuint directional_ubo;
@@ -169,11 +180,72 @@ public:
/* SHADOW ATLAS API */
+ uint64_t shadow_atlas_realloc_tolerance_msec;
+
+ struct ShadowAtlas : public RID_Data {
+ enum {
+ QUADRANT_SHIFT = 27,
+ SHADOW_INDEX_MASK = (1 << QUADRANT_SHIFT) - 1,
+ SHADOW_INVALID = 0xFFFFFFFF,
+ };
+
+ struct Quadrant {
+ uint32_t subdivision;
+
+ struct Shadow {
+ RID owner;
+ uint64_t version;
+ uint64_t alloc_tick;
+
+ Shadow() {
+ version = 0;
+ alloc_tick = 0;
+ }
+ };
+
+ Vector<Shadow> shadows;
+
+ Quadrant() {
+ subdivision = 0;
+ }
+ } quadrants[4];
+
+ int size_order[4];
+ uint32_t smallest_subdiv;
+
+ int size;
+
+ GLuint fbo;
+ GLuint depth;
+
+ Map<RID, uint32_t> shadow_owners;
+ };
+
+ struct ShadowCubeMap {
+ GLuint fbo[6];
+ GLuint cubemap;
+ uint32_t size;
+ };
+
+ Vector<ShadowCubeMap> shadow_cubemaps;
+
+ RID_Owner<ShadowAtlas> shadow_atlas_owner;
+
RID shadow_atlas_create();
void shadow_atlas_set_size(RID p_atlas, int p_size);
void shadow_atlas_set_quadrant_subdivision(RID p_atlas, int p_quadrant, int p_subdivision);
+ bool _shadow_atlas_find_shadow(ShadowAtlas *shadow_atlas, int *p_in_quadrants, int p_quadrant_count, int p_current_subdiv, uint64_t p_tick, int &r_quadrant, int &r_shadow);
bool shadow_atlas_update_light(RID p_atlas, RID p_light_intance, float p_coverage, uint64_t p_light_version);
+ struct DirectionalShadow {
+ GLuint fbo;
+ GLuint depth;
+
+ int light_count;
+ int size;
+ int current_light;
+ } directional_shadow;
+
virtual int get_directional_light_shadow_size(RID p_light_intance);
virtual void set_directional_shadow_count(int p_count);
@@ -196,6 +268,36 @@ public:
virtual bool reflection_probe_instance_postprocess_step(RID p_instance);
/* ENVIRONMENT API */
+
+ struct Environment : public RID_Data {
+ VS::EnvironmentBG bg_mode;
+
+ RID sky;
+ float sky_custom_fov;
+
+ Color bg_color;
+ float bg_energy;
+ float sky_ambient;
+
+ Color ambient_color;
+ float ambient_energy;
+ float ambient_sky_contribution;
+
+ int canvas_max_layer;
+
+ Environment() {
+ bg_mode = VS::ENV_BG_CLEAR_COLOR;
+ sky_custom_fov = 0.0;
+ bg_energy = 1.0;
+ sky_ambient = 0;
+ ambient_energy = 1.0;
+ ambient_sky_contribution = 0.0;
+ canvas_max_layer = 0;
+ }
+ };
+
+ mutable RID_Owner<Environment> environment_owner;
+
virtual RID environment_create();
virtual void environment_set_background(RID p_env, VS::EnvironmentBG p_bg);
@@ -212,7 +314,7 @@ public:
virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture);
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness);
- virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
+ virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
@@ -228,6 +330,43 @@ public:
virtual int environment_get_canvas_max_layer(RID p_env);
/* LIGHT INSTANCE */
+
+ struct LightInstance : public RID_Data {
+
+ struct ShadowTransform {
+ CameraMatrix camera;
+ Transform transform;
+ float farplane;
+ float split;
+ float bias_scale;
+ };
+
+ ShadowTransform shadow_transform[4];
+
+ RID self;
+ RID light;
+
+ RasterizerStorageGLES2::Light *light_ptr;
+ Transform transform;
+
+ Vector3 light_vector;
+ Vector3 spot_vector;
+ float linear_att;
+
+ // TODO passes and all that stuff ?
+ uint64_t last_scene_pass;
+ uint64_t last_scene_shadow_pass;
+
+ uint16_t light_index;
+ uint16_t light_directional_index;
+
+ Rect2 directional_rect;
+
+ Set<RID> shadow_atlases; // atlases where this light is registered
+ };
+
+ mutable RID_Owner<LightInstance> light_instance_owner;
+
virtual RID light_instance_create(RID p_light);
virtual void light_instance_set_transform(RID p_light_instance, const Transform &p_transform);
virtual void light_instance_set_shadow_transform(RID p_light_instance, const CameraMatrix &p_projection, const Transform &p_transform, float p_far, float p_split, int p_pass, float p_bias_scale = 1.0);
@@ -242,6 +381,192 @@ public:
/* RENDER LIST */
+ struct RenderList {
+ enum {
+ DEFAULT_MAX_ELEMENTS = 65536,
+ SORT_FLAG_SKELETON = 1,
+ SORT_FLAG_INSTANCING = 2,
+ MAX_DIRECTIONAL_LIGHTS = 16,
+ MAX_LIGHTS = 4096,
+ MAX_REFLECTIONS = 1024,
+
+ SORT_KEY_PRIORITY_SHIFT = 56,
+ SORT_KEY_PRIORITY_MASK = 0xFF,
+ //depth layer for opaque (56-52)
+ SORT_KEY_OPAQUE_DEPTH_LAYER_SHIFT = 52,
+ SORT_KEY_OPAQUE_DEPTH_LAYER_MASK = 0xF,
+//64 bits unsupported in MSVC
+#define SORT_KEY_UNSHADED_FLAG (uint64_t(1) << 49)
+#define SORT_KEY_NO_DIRECTIONAL_FLAG (uint64_t(1) << 48)
+#define SORT_KEY_LIGHTMAP_CAPTURE_FLAG (uint64_t(1) << 47)
+#define SORT_KEY_LIGHTMAP_FLAG (uint64_t(1) << 46)
+#define SORT_KEY_GI_PROBES_FLAG (uint64_t(1) << 45)
+#define SORT_KEY_VERTEX_LIT_FLAG (uint64_t(1) << 44)
+ SORT_KEY_SHADING_SHIFT = 44,
+ SORT_KEY_SHADING_MASK = 63,
+ //44-28 material index
+ SORT_KEY_MATERIAL_INDEX_SHIFT = 28,
+ //28-8 geometry index
+ SORT_KEY_GEOMETRY_INDEX_SHIFT = 8,
+ //bits 5-7 geometry type
+ SORT_KEY_GEOMETRY_TYPE_SHIFT = 5,
+ //bits 0-5 for flags
+ SORT_KEY_OPAQUE_PRE_PASS = 8,
+ SORT_KEY_CULL_DISABLED_FLAG = 4,
+ SORT_KEY_SKELETON_FLAG = 2,
+ SORT_KEY_MIRROR_FLAG = 1
+ };
+
+ int max_elements;
+
+ struct Element {
+ RasterizerScene::InstanceBase *instance;
+
+ RasterizerStorageGLES2::Geometry *geometry;
+ RasterizerStorageGLES2::Material *material;
+ RasterizerStorageGLES2::GeometryOwner *owner;
+
+ uint64_t sort_key;
+ };
+
+ Element *base_elements;
+ Element **elements;
+
+ int element_count;
+ int alpha_element_count;
+
+ void clear() {
+ element_count = 0;
+ alpha_element_count = 0;
+ }
+
+ // sorts
+
+ struct SortByKey {
+ _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
+ return A->sort_key < B->sort_key;
+ }
+ };
+
+ void sort_by_key(bool p_alpha) {
+ SortArray<Element *, SortByKey> sorter;
+
+ if (p_alpha) {
+ sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
+ } else {
+ sorter.sort(elements, element_count);
+ }
+ }
+
+ struct SortByDepth {
+
+ _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
+ return A->instance->depth < B->instance->depth;
+ }
+ };
+
+ void sort_by_depth(bool p_alpha) { //used for shadows
+
+ SortArray<Element *, SortByDepth> sorter;
+ if (p_alpha) {
+ sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
+ } else {
+ sorter.sort(elements, element_count);
+ }
+ }
+
+ struct SortByReverseDepthAndPriority {
+
+ _FORCE_INLINE_ bool operator()(const Element *A, const Element *B) const {
+ uint32_t layer_A = uint32_t(A->sort_key >> SORT_KEY_PRIORITY_SHIFT);
+ uint32_t layer_B = uint32_t(B->sort_key >> SORT_KEY_PRIORITY_SHIFT);
+ if (layer_A == layer_B) {
+ return A->instance->depth > B->instance->depth;
+ } else {
+ return layer_A < layer_B;
+ }
+ }
+ };
+
+ void sort_by_reverse_depth_and_priority(bool p_alpha) { //used for alpha
+
+ SortArray<Element *, SortByReverseDepthAndPriority> sorter;
+ if (p_alpha) {
+ sorter.sort(&elements[max_elements - alpha_element_count], alpha_element_count);
+ } else {
+ sorter.sort(elements, element_count);
+ }
+ }
+
+ // element adding and stuff
+
+ _FORCE_INLINE_ Element *add_element() {
+ if (element_count + alpha_element_count >= max_elements)
+ return NULL;
+
+ elements[element_count] = &base_elements[element_count];
+ return elements[element_count++];
+ }
+
+ _FORCE_INLINE_ Element *add_alpha_element() {
+ if (element_count + alpha_element_count >= max_elements) {
+ return NULL;
+ }
+
+ int idx = max_elements - alpha_element_count - 1;
+ elements[idx] = &base_elements[idx];
+ alpha_element_count++;
+ return elements[idx];
+ }
+
+ void init() {
+ element_count = 0;
+ alpha_element_count = 0;
+
+ elements = memnew_arr(Element *, max_elements);
+ base_elements = memnew_arr(Element, max_elements);
+
+ for (int i = 0; i < max_elements; i++) {
+ elements[i] = &base_elements[i];
+ }
+ }
+
+ RenderList() {
+ max_elements = DEFAULT_MAX_ELEMENTS;
+ }
+
+ ~RenderList() {
+ memdelete_arr(elements);
+ memdelete_arr(base_elements);
+ }
+ };
+
+ RenderList render_list;
+
+ void _add_geometry(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, int p_material, bool p_depth_pass, bool p_shadow_pass);
+ void _add_geometry_with_material(RasterizerStorageGLES2::Geometry *p_geometry, InstanceBase *p_instance, RasterizerStorageGLES2::GeometryOwner *p_owner, RasterizerStorageGLES2::Material *p_material, bool p_depth_pass, bool p_shadow_pass);
+
+ void _fill_render_list(InstanceBase **p_cull_result, int p_cull_count, bool p_depth_pass, bool p_shadow_pass);
+ void _render_render_list(RenderList::Element **p_elements, int p_element_count,
+ const RID *p_directional_lights, int p_directional_light_count,
+ const Transform &p_view_transform,
+ const CameraMatrix &p_projection,
+ RID p_shadow_atlas,
+ Environment *p_env,
+ GLuint p_base_env,
+ float p_shadow_bias,
+ float p_shadow_normal_bias,
+ bool p_reverse_cull,
+ bool p_alpha_pass,
+ bool p_shadow,
+ bool p_directional_add);
+
+ void _draw_sky(RasterizerStorageGLES2::Sky *p_sky, const CameraMatrix &p_projection, const Transform &p_transform, bool p_vflip, float p_custom_fov, float p_energy);
+
+ void _setup_material(RasterizerStorageGLES2::Material *p_material, bool p_reverse_cull, bool p_alpha_pass, Size2i p_skeleton_tex_size = Size2i(0, 0));
+ void _setup_geometry(RenderList::Element *p_element, RasterizerStorageGLES2::Skeleton *p_skeleton);
+ void _render_geometry(RenderList::Element *p_element);
+
virtual void render_scene(const Transform &p_cam_transform, const CameraMatrix &p_cam_projection, bool p_cam_ortogonal, InstanceBase **p_cull_result, int p_cull_count, RID *p_light_cull_result, int p_light_cull_count, RID *p_reflection_probe_cull_result, int p_reflection_probe_cull_count, RID p_environment, RID p_shadow_atlas, RID p_reflection_atlas, RID p_reflection_probe, int p_reflection_probe_pass);
virtual void render_shadow(RID p_light, RID p_shadow_atlas, int p_pass, InstanceBase **p_cull_result, int p_cull_count);
virtual bool free(RID p_rid);
diff --git a/drivers/gles2/rasterizer_storage_gles2.cpp b/drivers/gles2/rasterizer_storage_gles2.cpp
index ec12999c2c..5b5ab987d1 100644
--- a/drivers/gles2/rasterizer_storage_gles2.cpp
+++ b/drivers/gles2/rasterizer_storage_gles2.cpp
@@ -28,18 +28,46 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#include "rasterizer_storage_gles2.h"
+
#include "project_settings.h"
#include "rasterizer_canvas_gles2.h"
#include "rasterizer_scene_gles2.h"
+#include "math/transform.h"
+
+#include "servers/visual/shader_language.h"
+
GLuint RasterizerStorageGLES2::system_fbo = 0;
/* TEXTURE API */
-Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type) {
+#define _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT 0x83F1
+#define _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT 0x83F2
+#define _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT 0x83F3
+
+#define _EXT_ETC1_RGB8_OES 0x8D64
+
+#ifdef GLES_OVER_GL
+#define _GL_HALF_FLOAT_OES 0x140B
+#else
+#define _GL_HALF_FLOAT_OES 0x8D61
+#endif
+
+void RasterizerStorageGLES2::bind_quad_array() const {
+ glBindBuffer(GL_ARRAY_BUFFER, resources.quadie);
+ glVertexAttribPointer(VS::ARRAY_VERTEX, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, 0);
+ glVertexAttribPointer(VS::ARRAY_TEX_UV, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, ((uint8_t *)NULL) + 8);
+
+ glEnableVertexAttribArray(VS::ARRAY_VERTEX);
+ glEnableVertexAttribArray(VS::ARRAY_TEX_UV);
+}
+
+Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const {
r_gl_format = 0;
Ref<Image> image = p_image;
+ r_compressed = false;
+ r_real_format = p_format;
bool need_decompress = false;
@@ -98,9 +126,14 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
} break;
case Image::FORMAT_RF: {
- ERR_EXPLAIN("R float texture not supported");
- ERR_FAIL_V(image);
+ if (!config.float_texture_supported) {
+ ERR_EXPLAIN("R float texture not supported");
+ ERR_FAIL_V(image);
+ }
+ r_gl_internal_format = GL_ALPHA;
+ r_gl_format = GL_ALPHA;
+ r_gl_type = GL_FLOAT;
} break;
case Image::FORMAT_RGF: {
ERR_EXPLAIN("RG float texture not supported");
@@ -108,54 +141,87 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
} break;
case Image::FORMAT_RGBF: {
+ if (!config.float_texture_supported) {
- ERR_EXPLAIN("RGB float texture not supported");
- ERR_FAIL_V(image);
+ ERR_EXPLAIN("RGB float texture not supported");
+ ERR_FAIL_V(image);
+ }
+
+ r_gl_internal_format = GL_RGB;
+ r_gl_format = GL_RGB;
+ r_gl_type = GL_FLOAT;
} break;
case Image::FORMAT_RGBAF: {
+ if (!config.float_texture_supported) {
- ERR_EXPLAIN("RGBA float texture not supported");
- ERR_FAIL_V(image);
+ ERR_EXPLAIN("RGBA float texture not supported");
+ ERR_FAIL_V(image);
+ }
+
+ r_gl_internal_format = GL_RGBA;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_FLOAT;
} break;
case Image::FORMAT_RH: {
- ERR_EXPLAIN("R half float texture not supported");
- ERR_FAIL_V(image);
+ need_decompress = true;
} break;
case Image::FORMAT_RGH: {
- ERR_EXPLAIN("RG half float texture not supported");
- ERR_FAIL_V(image);
-
+ need_decompress = true;
} break;
case Image::FORMAT_RGBH: {
- ERR_EXPLAIN("RGB half float texture not supported");
- ERR_FAIL_V(image);
-
+ need_decompress = true;
} break;
case Image::FORMAT_RGBAH: {
- ERR_EXPLAIN("RGBA half float texture not supported");
- ERR_FAIL_V(image);
-
+ need_decompress = true;
} break;
case Image::FORMAT_RGBE9995: {
- ERR_EXPLAIN("RGBA float texture not supported");
- ERR_FAIL_V(image);
+ r_gl_internal_format = GL_RGB;
+ r_gl_format = GL_RGB;
+ r_gl_type = GL_UNSIGNED_BYTE;
+
+ if (image.is_valid())
+
+ image = image->rgbe_to_srgb();
+
+ return image;
} break;
case Image::FORMAT_DXT1: {
- need_decompress = true;
+ r_compressed = true;
+ if (config.s3tc_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT1_EXT;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ } else {
+ need_decompress = true;
+ }
} break;
case Image::FORMAT_DXT3: {
- need_decompress = true;
+ if (config.s3tc_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+ } else {
+ need_decompress = true;
+ }
} break;
case Image::FORMAT_DXT5: {
- need_decompress = true;
+ if (config.s3tc_supported) {
+ r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+ } else {
+ need_decompress = true;
+ }
} break;
case Image::FORMAT_RGTC_R: {
@@ -198,7 +264,14 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
} break;
case Image::FORMAT_ETC: {
- need_decompress = true;
+ if (config.etc1_supported) {
+ r_gl_internal_format = _EXT_ETC1_RGB8_OES;
+ r_gl_format = GL_RGBA;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ r_compressed = true;
+ } else {
+ need_decompress = true;
+ }
} break;
case Image::FORMAT_ETC2_R11: {
@@ -246,6 +319,7 @@ Ref<Image> RasterizerStorageGLES2::_get_gl_image_and_format(const Ref<Image> &p_
r_gl_format = GL_RGBA;
r_gl_internal_format = GL_RGBA;
r_gl_type = GL_UNSIGNED_BYTE;
+ r_real_format = Image::FORMAT_RGBA8;
return image;
}
@@ -275,11 +349,14 @@ RID RasterizerStorageGLES2::texture_create() {
return texture_owner.make_rid(texture);
}
-void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
+void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type, uint32_t p_flags) {
GLenum format;
GLenum internal_format;
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
}
@@ -291,9 +368,31 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
texture->format = p_format;
texture->flags = p_flags;
texture->stored_cube_sides = 0;
- texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
+ texture->type = p_type;
+
+ switch (p_type) {
+ case VS::TEXTURE_TYPE_2D: {
+ texture->target = GL_TEXTURE_2D;
+ texture->images.resize(1);
+ } break;
+ case VS::TEXTURE_TYPE_CUBEMAP: {
+ texture->target = GL_TEXTURE_CUBE_MAP;
+ texture->images.resize(6);
+ } break;
+ case VS::TEXTURE_TYPE_2D_ARRAY: {
+ texture->images.resize(p_depth_3d);
+ } break;
+ case VS::TEXTURE_TYPE_3D: {
+ texture->images.resize(p_depth_3d);
+ } break;
+ default: {
+ ERR_PRINT("Unknown texture type!");
+ return;
+ }
+ }
- _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, format, internal_format, type);
+ Image::Format real_format;
+ _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed);
texture->alloc_width = texture->width;
texture->alloc_height = texture->height;
@@ -304,6 +403,8 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
texture->data_size = 0;
texture->mipmaps = 1;
+ texture->compressed = compressed;
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
@@ -315,7 +416,7 @@ void RasterizerStorageGLES2::texture_allocate(RID p_texture, int p_width, int p_
texture->active = true;
}
-void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side) {
+void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) {
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
@@ -328,13 +429,13 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
GLenum format;
GLenum internal_format;
bool compressed = false;
- bool srgb;
if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
- texture->images[p_cube_side] = p_image;
+ texture->images.write[p_layer] = p_image;
}
- Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type);
+ Image::Format real_format;
+ Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed);
if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
@@ -350,7 +451,7 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
}
};
- GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D;
+ GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_layer] : GL_TEXTURE_2D;
texture->data_size = img->get_data().size();
PoolVector<uint8_t>::Read read = img->get_data().read();
@@ -423,11 +524,21 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
int size, ofs;
img->get_mipmap_offset_and_size(i, ofs, size);
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
- glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]);
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ int bw = w;
+ int bh = h;
+
+ glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
} else {
- glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]);
+ } else {
+ glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ }
}
tsize += size;
@@ -442,9 +553,9 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
// printf("texture: %i x %i - size: %i - total: %i\n", texture->width, texture->height, tsize, info.texture_mem);
- texture->stored_cube_sides |= (1 << p_cube_side);
+ texture->stored_cube_sides |= (1 << p_layer);
- if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides == (1 << 6) - 1)) {
+ if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != VS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) {
//generate mipmaps if they were requested and the image does not contain them
glGenerateMipmap(texture->target);
}
@@ -452,12 +563,12 @@ void RasterizerStorageGLES2::texture_set_data(RID p_texture, const Ref<Image> &p
texture->mipmaps = mipmaps;
}
-void RasterizerStorageGLES2::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) {
+void RasterizerStorageGLES2::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) {
// TODO
ERR_PRINT("Not implemented (ask Karroffel to do it :p)");
}
-Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side) const {
+Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, int p_layer) const {
Texture *texture = texture_owner.getornull(p_texture);
@@ -465,14 +576,22 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSi
ERR_FAIL_COND_V(!texture->active, Ref<Image>());
ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>());
- if (!texture->images[p_cube_side].is_null()) {
- return texture->images[p_cube_side];
+ if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && p_layer >= 0 && !texture->images[p_layer].is_null()) {
+ return texture->images[p_layer];
}
+
#ifdef GLES_OVER_GL
+ 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, texture->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 ? -1 : 0);
data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
PoolVector<uint8_t>::Write wb = data.write();
@@ -483,25 +602,27 @@ Ref<Image> RasterizerStorageGLES2::texture_get_data(RID p_texture, VS::CubeMapSi
glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
- //print_line("GET FORMAT: " + Image::get_format_name(texture->format) + " mipmaps: " + itos(texture->mipmaps));
-
for (int i = 0; i < texture->mipmaps; i++) {
int ofs = 0;
if (i > 0) {
- ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->format, i - 1);
+ ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1);
}
- glPixelStorei(GL_PACK_ALIGNMENT, 1);
-
- glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]);
+ if (texture->compressed) {
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ glGetCompressedTexImage(texture->target, i, &wb[ofs]);
+ } else {
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &wb[ofs]);
+ }
}
wb = PoolVector<uint8_t>::Write();
data.resize(data_size);
- Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, texture->format, data));
+ Image *img = memnew(Image(texture->alloc_width, texture->alloc_height, texture->mipmaps > 1 ? true : false, real_format, data));
return Ref<Image>(img);
#else
@@ -518,10 +639,10 @@ void RasterizerStorageGLES2::texture_set_flags(RID p_texture, uint32_t p_flags)
bool had_mipmaps = texture->flags & VS::TEXTURE_FLAG_MIPMAPS;
+ texture->flags = p_flags;
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP;
- texture->flags = p_flags | cube; // can't remove a cube from being a cube
if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
@@ -578,6 +699,14 @@ Image::Format RasterizerStorageGLES2::texture_get_format(RID p_texture) const {
return texture->format;
}
+VisualServer::TextureType RasterizerStorageGLES2::texture_get_type(RID p_texture) const {
+ Texture *texture = texture_owner.getornull(p_texture);
+
+ ERR_FAIL_COND_V(!texture, VS::TEXTURE_TYPE_2D);
+
+ return texture->type;
+}
+
uint32_t RasterizerStorageGLES2::texture_get_texid(RID p_texture) const {
Texture *texture = texture_owner.getornull(p_texture);
@@ -602,7 +731,15 @@ uint32_t RasterizerStorageGLES2::texture_get_height(RID p_texture) const {
return texture->height;
}
-void RasterizerStorageGLES2::texture_set_size_override(RID p_texture, int p_width, int p_height) {
+uint32_t RasterizerStorageGLES2::texture_get_depth(RID p_texture) const {
+ Texture *texture = texture_owner.getornull(p_texture);
+
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->depth;
+}
+
+void RasterizerStorageGLES2::texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth) {
Texture *texture = texture_owner.getornull(p_texture);
ERR_FAIL_COND(!texture);
@@ -641,8 +778,9 @@ void RasterizerStorageGLES2::texture_debug_usage(List<VS::TextureInfo> *r_info)
VS::TextureInfo tinfo;
tinfo.path = t->path;
tinfo.format = t->format;
- tinfo.size.x = t->alloc_width;
- tinfo.size.y = t->alloc_height;
+ tinfo.width = t->alloc_width;
+ tinfo.height = t->alloc_height;
+ tinfo.depth = 0;
tinfo.bytes = t->total_data_size;
r_info->push_back(tinfo);
}
@@ -674,28 +812,180 @@ void RasterizerStorageGLES2::texture_set_proxy(RID p_texture, RID p_proxy) {
}
}
+void RasterizerStorageGLES2::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {
+
+ Texture *texture = texture_owner.getornull(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->redraw_if_visible = p_enable;
+}
+
void RasterizerStorageGLES2::texture_set_detect_3d_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {
- // TODO
+ Texture *texture = texture_owner.get(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->detect_3d = p_callback;
+ texture->detect_3d_ud = p_userdata;
}
void RasterizerStorageGLES2::texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {
- // TODO
+ Texture *texture = texture_owner.get(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->detect_srgb = p_callback;
+ texture->detect_srgb_ud = p_userdata;
}
void RasterizerStorageGLES2::texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata) {
- // TODO
+ Texture *texture = texture_owner.get(p_texture);
+ ERR_FAIL_COND(!texture);
+
+ texture->detect_normal = p_callback;
+ texture->detect_normal_ud = p_userdata;
}
RID RasterizerStorageGLES2::texture_create_radiance_cubemap(RID p_source, int p_resolution) const {
- // TODO
+
return RID();
}
RID RasterizerStorageGLES2::sky_create() {
- return RID();
+ Sky *sky = memnew(Sky);
+ sky->radiance = 0;
+ return sky_owner.make_rid(sky);
}
void RasterizerStorageGLES2::sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size) {
+ Sky *sky = sky_owner.getornull(p_sky);
+ ERR_FAIL_COND(!sky);
+
+ if (sky->panorama.is_valid()) {
+ sky->panorama = RID();
+ glDeleteTextures(1, &sky->radiance);
+ sky->radiance = 0;
+ }
+
+ sky->panorama = p_panorama;
+ if (!sky->panorama.is_valid()) {
+ return; // the panorama was cleared
+ }
+
+ Texture *texture = texture_owner.getornull(sky->panorama);
+ if (!texture) {
+ sky->panorama = RID();
+ ERR_FAIL_COND(!texture);
+ }
+
+ // glBindVertexArray(0) and more
+ {
+ 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);
+
+ for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ glDisableVertexAttribArray(i);
+ }
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(texture->target, texture->tex_id);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //need this for proper sampling
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, resources.radical_inverse_vdc_cache_tex);
+
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+
+ // New cubemap that will hold the mipmaps with different roughness values
+ glActiveTexture(GL_TEXTURE2);
+ glGenTextures(1, &sky->radiance);
+ glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance);
+
+ // Now we create a new framebuffer. The new cubemap images will be used as
+ // attachements for it, so we can fill them by issuing draw calls.
+ GLuint tmp_fb;
+
+ glGenFramebuffers(1, &tmp_fb);
+ glBindFramebuffer(GL_FRAMEBUFFER, tmp_fb);
+
+ int size = p_radiance_size;
+
+ 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?
+
+ // Set the initial (empty) mipmaps
+ while (size >= 1) {
+
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(_cube_side_enum[i], lod, internal_format, size, size, 0, format, type, NULL);
+ }
+
+ lod++;
+
+ size >>= 1;
+ }
+
+ lod = 0;
+ mm_level = mipmaps;
+
+ size = p_radiance_size;
+
+ // now render to the framebuffer, mipmap level for mipmap level
+ while (size >= 1) {
+
+ for (int i = 0; i < 6; i++) {
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, _cube_side_enum[i], sky->radiance, lod);
+
+ glViewport(0, 0, size, size);
+
+ bind_quad_array();
+
+ shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::FACE_ID, i);
+
+ float roughness = mm_level ? lod / (float)(mipmaps - 1) : 1;
+ shaders.cubemap_filter.set_uniform(CubemapFilterShaderGLES2::ROUGHNESS, roughness);
+
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+
+ size >>= 1;
+
+ mm_level--;
+
+ lod++;
+ }
+
+ // restore ranges
+
+ glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
+ 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);
+
+ // Framebuffer did its job. thank mr framebuffer
+ glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES2::system_fbo);
+ glDeleteFramebuffers(1, &tmp_fb);
}
/* SHADER API */
@@ -747,6 +1037,8 @@ void RasterizerStorageGLES2::shader_set_code(RID p_shader, const String &p_code)
if (mode == VS::SHADER_CANVAS_ITEM) {
shader->shader = &canvas->state.canvas_shader;
+ } else if (mode == VS::SHADER_SPATIAL) {
+ shader->shader = &scene->state.scene_shader;
} else {
return;
}
@@ -807,6 +1099,62 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
actions->uniforms = &p_shader->uniforms;
} break;
+ case VS::SHADER_SPATIAL: {
+ p_shader->spatial.blend_mode = Shader::Spatial::BLEND_MODE_MIX;
+ p_shader->spatial.depth_draw_mode = Shader::Spatial::DEPTH_DRAW_OPAQUE;
+ p_shader->spatial.cull_mode = Shader::Spatial::CULL_MODE_BACK;
+ p_shader->spatial.uses_alpha = false;
+ p_shader->spatial.uses_alpha_scissor = false;
+ p_shader->spatial.uses_discard = false;
+ p_shader->spatial.unshaded = false;
+ p_shader->spatial.no_depth_test = false;
+ p_shader->spatial.uses_sss = false;
+ p_shader->spatial.uses_time = false;
+ p_shader->spatial.uses_vertex_lighting = false;
+ p_shader->spatial.uses_screen_texture = false;
+ p_shader->spatial.uses_depth_texture = false;
+ p_shader->spatial.uses_vertex = false;
+ p_shader->spatial.writes_modelview_or_projection = false;
+ p_shader->spatial.uses_world_coordinates = false;
+
+ shaders.actions_scene.render_mode_values["blend_add"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_ADD);
+ shaders.actions_scene.render_mode_values["blend_mix"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MIX);
+ shaders.actions_scene.render_mode_values["blend_sub"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_SUB);
+ shaders.actions_scene.render_mode_values["blend_mul"] = Pair<int *, int>(&p_shader->spatial.blend_mode, Shader::Spatial::BLEND_MODE_MUL);
+
+ shaders.actions_scene.render_mode_values["depth_draw_opaque"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_OPAQUE);
+ shaders.actions_scene.render_mode_values["depth_draw_always"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALWAYS);
+ shaders.actions_scene.render_mode_values["depth_draw_never"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_NEVER);
+ shaders.actions_scene.render_mode_values["depth_draw_alpha_prepass"] = Pair<int *, int>(&p_shader->spatial.depth_draw_mode, Shader::Spatial::DEPTH_DRAW_ALPHA_PREPASS);
+
+ shaders.actions_scene.render_mode_values["cull_front"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_FRONT);
+ shaders.actions_scene.render_mode_values["cull_back"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_BACK);
+ shaders.actions_scene.render_mode_values["cull_disabled"] = Pair<int *, int>(&p_shader->spatial.cull_mode, Shader::Spatial::CULL_MODE_DISABLED);
+
+ shaders.actions_scene.render_mode_flags["unshaded"] = &p_shader->spatial.unshaded;
+ shaders.actions_scene.render_mode_flags["depth_test_disable"] = &p_shader->spatial.no_depth_test;
+
+ shaders.actions_scene.render_mode_flags["vertex_lighting"] = &p_shader->spatial.uses_vertex_lighting;
+
+ shaders.actions_scene.render_mode_flags["world_vertex_coords"] = &p_shader->spatial.uses_world_coordinates;
+
+ shaders.actions_scene.usage_flag_pointers["ALPHA"] = &p_shader->spatial.uses_alpha;
+ shaders.actions_scene.usage_flag_pointers["ALPHA_SCISSOR"] = &p_shader->spatial.uses_alpha_scissor;
+
+ shaders.actions_scene.usage_flag_pointers["SSS_STRENGTH"] = &p_shader->spatial.uses_sss;
+ shaders.actions_scene.usage_flag_pointers["DISCARD"] = &p_shader->spatial.uses_discard;
+ shaders.actions_scene.usage_flag_pointers["SCREEN_TEXTURE"] = &p_shader->spatial.uses_screen_texture;
+ shaders.actions_scene.usage_flag_pointers["DEPTH_TEXTURE"] = &p_shader->spatial.uses_depth_texture;
+ shaders.actions_scene.usage_flag_pointers["TIME"] = &p_shader->spatial.uses_time;
+
+ shaders.actions_scene.write_flag_pointers["MODELVIEW_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection;
+ shaders.actions_scene.write_flag_pointers["PROJECTION_MATRIX"] = &p_shader->spatial.writes_modelview_or_projection;
+ shaders.actions_scene.write_flag_pointers["VERTEX"] = &p_shader->spatial.uses_vertex;
+
+ actions = &shaders.actions_scene;
+ actions->uniforms = &p_shader->uniforms;
+ } break;
+
default: {
return;
} break;
@@ -824,6 +1172,11 @@ void RasterizerStorageGLES2::_update_shader(Shader *p_shader) const {
p_shader->uses_vertex_time = gen_code.uses_vertex_time;
p_shader->uses_fragment_time = gen_code.uses_fragment_time;
+ p_shader->shader->set_custom_shader(p_shader->custom_code_id);
+ p_shader->shader->bind();
+
+ // cache uniform locations
+
for (SelfList<Material> *E = p_shader->materials.first(); E; E = E->next()) {
_material_make_dirty(E->self());
}
@@ -911,6 +1264,10 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn
pi.type = Variant::POOL_INT_ARRAY;
} break;
+ case ShaderLanguage::TYPE_FLOAT: {
+ pi.type = Variant::REAL;
+ } break;
+
case ShaderLanguage::TYPE_VEC2: {
pi.type = Variant::VECTOR2;
} break;
@@ -951,6 +1308,10 @@ void RasterizerStorageGLES2::shader_get_param_list(RID p_shader, List<PropertyIn
pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
pi.hint_string = "CubeMap";
} break;
+
+ default: {
+
+ } break;
}
p_param_list->push_back(pi);
@@ -1063,335 +1424,1864 @@ Variant RasterizerStorageGLES2::material_get_param(RID p_material, const StringN
}
void RasterizerStorageGLES2::material_set_line_width(RID p_material, float p_width) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ material->line_width = p_width;
}
void RasterizerStorageGLES2::material_set_next_pass(RID p_material, RID p_next_material) {
+ Material *material = material_owner.get(p_material);
+ ERR_FAIL_COND(!material);
+
+ material->next_pass = p_next_material;
}
bool RasterizerStorageGLES2::material_is_animated(RID p_material) {
- return false;
+ Material *material = material_owner.get(p_material);
+ ERR_FAIL_COND_V(!material, false);
+ if (material->dirty_list.in_list()) {
+ _update_material(material);
+ }
+
+ bool animated = material->is_animated_cache;
+ if (!animated && material->next_pass.is_valid()) {
+ animated = material_is_animated(material->next_pass);
+ }
+ return animated;
}
bool RasterizerStorageGLES2::material_casts_shadows(RID p_material) {
- return false;
+ Material *material = material_owner.get(p_material);
+ ERR_FAIL_COND_V(!material, false);
+ if (material->dirty_list.in_list()) {
+ _update_material(material);
+ }
+
+ bool casts_shadows = material->can_cast_shadow_cache;
+
+ if (!casts_shadows && material->next_pass.is_valid()) {
+ casts_shadows = material_casts_shadows(material->next_pass);
+ }
+
+ return casts_shadows;
}
void RasterizerStorageGLES2::material_add_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.find(p_instance);
+ if (E) {
+ E->get()++;
+ } else {
+ material->instance_owners[p_instance] = 1;
+ }
}
void RasterizerStorageGLES2::material_remove_instance_owner(RID p_material, RasterizerScene::InstanceBase *p_instance) {
+
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ Map<RasterizerScene::InstanceBase *, int>::Element *E = material->instance_owners.find(p_instance);
+ ERR_FAIL_COND(!E);
+
+ E->get()--;
+
+ if (E->get() == 0) {
+ material->instance_owners.erase(E);
+ }
}
void RasterizerStorageGLES2::material_set_render_priority(RID p_material, int priority) {
+ ERR_FAIL_COND(priority < VS::MATERIAL_RENDER_PRIORITY_MIN);
+ ERR_FAIL_COND(priority > VS::MATERIAL_RENDER_PRIORITY_MAX);
+
+ Material *material = material_owner.get(p_material);
+ ERR_FAIL_COND(!material);
+
+ material->render_priority = priority;
+}
+
+void RasterizerStorageGLES2::_update_material(Material *p_material) {
+ if (p_material->dirty_list.in_list()) {
+ _material_dirty_list.remove(&p_material->dirty_list);
+ }
+
+ if (p_material->shader && p_material->shader->dirty_list.in_list()) {
+ _update_shader(p_material->shader);
+ }
+
+ if (p_material->shader && !p_material->shader->valid) {
+ return;
+ }
+
+ {
+ bool can_cast_shadow = false;
+ bool is_animated = false;
+
+ 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))) {
+ can_cast_shadow = true;
+ }
+
+ if (p_material->shader->spatial.uses_discard && p_material->shader->uses_fragment_time) {
+ is_animated = true;
+ }
+
+ if (p_material->shader->spatial.uses_vertex && p_material->shader->uses_vertex_time) {
+ is_animated = true;
+ }
+
+ if (can_cast_shadow != p_material->can_cast_shadow_cache || is_animated != p_material->is_animated_cache) {
+ p_material->can_cast_shadow_cache = can_cast_shadow;
+ p_material->is_animated_cache = is_animated;
+
+ for (Map<Geometry *, int>::Element *E = p_material->geometry_owners.front(); E; E = E->next()) {
+ E->key()->material_changed_notify();
+ }
+
+ for (Map<RasterizerScene::InstanceBase *, int>::Element *E = p_material->instance_owners.front(); E; E = E->next()) {
+ E->key()->base_material_changed();
+ }
+ }
+ }
+ }
+
+ // uniforms and other thigns will be set in the use_material method in ShaderGLES2
+
+ if (p_material->shader && p_material->shader->texture_count > 0) {
+
+ p_material->textures.resize(p_material->shader->texture_count);
+
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = p_material->shader->uniforms.front(); E; E = E->next()) {
+ if (E->get().texture_order < 0)
+ continue; // not a texture, does not go here
+
+ RID texture;
+
+ Map<StringName, Variant>::Element *V = p_material->params.find(E->key());
+
+ if (V) {
+ texture = V->get();
+ }
+
+ if (!texture.is_valid()) {
+ Map<StringName, RID>::Element *W = p_material->shader->default_textures.find(E->key());
+
+ if (W) {
+ texture = W->get();
+ }
+ }
+
+ p_material->textures.write[E->get().texture_order] = Pair<StringName, RID>(E->key(), texture);
+ }
+ } else {
+ p_material->textures.clear();
+ }
+}
+
+void RasterizerStorageGLES2::_material_add_geometry(RID p_material, Geometry *p_geometry) {
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ Map<Geometry *, int>::Element *I = material->geometry_owners.find(p_geometry);
+
+ if (I) {
+ I->get()++;
+ } else {
+ material->geometry_owners[p_geometry] = 1;
+ }
+}
+
+void RasterizerStorageGLES2::_material_remove_geometry(RID p_material, Geometry *p_geometry) {
+
+ Material *material = material_owner.getornull(p_material);
+ ERR_FAIL_COND(!material);
+
+ Map<Geometry *, int>::Element *I = material->geometry_owners.find(p_geometry);
+ ERR_FAIL_COND(!I);
+
+ I->get()--;
+
+ if (I->get() == 0) {
+ material->geometry_owners.erase(I);
+ }
}
void RasterizerStorageGLES2::update_dirty_materials() {
+ while (_material_dirty_list.first()) {
+
+ Material *material = _material_dirty_list.first()->self();
+ _update_material(material);
+ }
}
/* MESH API */
RID RasterizerStorageGLES2::mesh_create() {
- return RID();
+
+ Mesh *mesh = memnew(Mesh);
+
+ return mesh_owner.make_rid(mesh);
}
void RasterizerStorageGLES2::mesh_add_surface(RID p_mesh, uint32_t p_format, VS::PrimitiveType p_primitive, const PoolVector<uint8_t> &p_array, int p_vertex_count, const PoolVector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<PoolVector<uint8_t> > &p_blend_shapes, const Vector<AABB> &p_bone_aabbs) {
+ PoolVector<uint8_t> array = p_array;
+
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ ERR_FAIL_COND(!(p_format & VS::ARRAY_FORMAT_VERTEX));
+
+ //must have index and bones, both.
+ {
+ uint32_t bones_weight = VS::ARRAY_FORMAT_BONES | VS::ARRAY_FORMAT_WEIGHTS;
+ ERR_EXPLAIN("Array must have both bones and weights in format or none.");
+ ERR_FAIL_COND((p_format & bones_weight) && (p_format & bones_weight) != bones_weight);
+ }
+
+ //bool has_morph = p_blend_shapes.size();
+
+ Surface::Attrib attribs[VS::ARRAY_MAX];
+
+ int stride = 0;
+
+ for (int i = 0; i < VS::ARRAY_MAX; i++) {
+
+ attribs[i].index = i;
+
+ if (!(p_format & (1 << i))) {
+ attribs[i].enabled = false;
+ attribs[i].integer = false;
+ continue;
+ }
+
+ attribs[i].enabled = true;
+ attribs[i].offset = stride;
+ attribs[i].integer = false;
+
+ switch (i) {
+
+ case VS::ARRAY_VERTEX: {
+
+ if (p_format & VS::ARRAY_FLAG_USE_2D_VERTICES) {
+ attribs[i].size = 2;
+ } else {
+ attribs[i].size = (p_format & VS::ARRAY_COMPRESS_VERTEX) ? 4 : 3;
+ }
+
+ if (p_format & VS::ARRAY_COMPRESS_VERTEX) {
+ attribs[i].type = _GL_HALF_FLOAT_OES;
+ stride += attribs[i].size * 2;
+ } else {
+ attribs[i].type = GL_FLOAT;
+ stride += attribs[i].size * 4;
+ }
+
+ attribs[i].normalized = GL_FALSE;
+
+ } break;
+ case VS::ARRAY_NORMAL: {
+
+ attribs[i].size = 3;
+
+ if (p_format & VS::ARRAY_COMPRESS_NORMAL) {
+ attribs[i].type = GL_BYTE;
+ stride += 4; //pad extra byte
+ attribs[i].normalized = GL_TRUE;
+ } else {
+ attribs[i].type = GL_FLOAT;
+ stride += 12;
+ attribs[i].normalized = GL_FALSE;
+ }
+
+ } break;
+ case VS::ARRAY_TANGENT: {
+
+ attribs[i].size = 4;
+
+ if (p_format & VS::ARRAY_COMPRESS_TANGENT) {
+ attribs[i].type = GL_BYTE;
+ stride += 4;
+ attribs[i].normalized = GL_TRUE;
+ } else {
+ attribs[i].type = GL_FLOAT;
+ stride += 16;
+ attribs[i].normalized = GL_FALSE;
+ }
+
+ } break;
+ case VS::ARRAY_COLOR: {
+
+ attribs[i].size = 4;
+
+ if (p_format & VS::ARRAY_COMPRESS_COLOR) {
+ attribs[i].type = GL_UNSIGNED_BYTE;
+ stride += 4;
+ attribs[i].normalized = GL_TRUE;
+ } else {
+ attribs[i].type = GL_FLOAT;
+ stride += 16;
+ attribs[i].normalized = GL_FALSE;
+ }
+
+ } break;
+ case VS::ARRAY_TEX_UV: {
+
+ attribs[i].size = 2;
+
+ if (p_format & VS::ARRAY_COMPRESS_TEX_UV) {
+ attribs[i].type = _GL_HALF_FLOAT_OES;
+ stride += 4;
+ } else {
+ attribs[i].type = GL_FLOAT;
+ stride += 8;
+ }
+
+ attribs[i].normalized = GL_FALSE;
+
+ } break;
+ case VS::ARRAY_TEX_UV2: {
+
+ attribs[i].size = 2;
+
+ if (p_format & VS::ARRAY_COMPRESS_TEX_UV2) {
+ attribs[i].type = _GL_HALF_FLOAT_OES;
+ stride += 4;
+ } else {
+ attribs[i].type = GL_FLOAT;
+ stride += 8;
+ }
+ attribs[i].normalized = GL_FALSE;
+
+ } break;
+ case VS::ARRAY_BONES: {
+
+ attribs[i].size = 4;
+
+ if (p_format & VS::ARRAY_FLAG_USE_16_BIT_BONES) {
+ attribs[i].type = GL_UNSIGNED_SHORT;
+ stride += 8;
+ } else {
+ attribs[i].type = GL_UNSIGNED_BYTE;
+ stride += 4;
+ }
+
+ attribs[i].normalized = GL_FALSE;
+ attribs[i].integer = true;
+
+ } break;
+ case VS::ARRAY_WEIGHTS: {
+
+ attribs[i].size = 4;
+
+ if (p_format & VS::ARRAY_COMPRESS_WEIGHTS) {
+
+ attribs[i].type = GL_UNSIGNED_SHORT;
+ stride += 8;
+ attribs[i].normalized = GL_TRUE;
+ } else {
+ attribs[i].type = GL_FLOAT;
+ stride += 16;
+ attribs[i].normalized = GL_FALSE;
+ }
+
+ } break;
+ case VS::ARRAY_INDEX: {
+
+ attribs[i].size = 1;
+
+ if (p_vertex_count >= (1 << 16)) {
+ attribs[i].type = GL_UNSIGNED_INT;
+ attribs[i].stride = 4;
+ } else {
+ attribs[i].type = GL_UNSIGNED_SHORT;
+ attribs[i].stride = 2;
+ }
+
+ attribs[i].normalized = GL_FALSE;
+
+ } break;
+ }
+ }
+
+ for (int i = 0; i < VS::ARRAY_MAX - 1; i++) {
+ attribs[i].stride = stride;
+ }
+
+ //validate sizes
+
+ int array_size = stride * p_vertex_count;
+ int index_array_size = 0;
+ if (array.size() != array_size && array.size() + p_vertex_count * 2 == array_size) {
+ //old format, convert
+ array = PoolVector<uint8_t>();
+
+ array.resize(p_array.size() + p_vertex_count * 2);
+
+ PoolVector<uint8_t>::Write w = array.write();
+ PoolVector<uint8_t>::Read r = p_array.read();
+
+ uint16_t *w16 = (uint16_t *)w.ptr();
+ const uint16_t *r16 = (uint16_t *)r.ptr();
+
+ uint16_t one = Math::make_half_float(1);
+
+ for (int i = 0; i < p_vertex_count; i++) {
+
+ *w16++ = *r16++;
+ *w16++ = *r16++;
+ *w16++ = *r16++;
+ *w16++ = one;
+ for (int j = 0; j < (stride / 2) - 4; j++) {
+ *w16++ = *r16++;
+ }
+ }
+ }
+
+ ERR_FAIL_COND(array.size() != array_size);
+
+ if (p_format & VS::ARRAY_FORMAT_INDEX) {
+
+ index_array_size = attribs[VS::ARRAY_INDEX].stride * p_index_count;
+ }
+
+ ERR_FAIL_COND(p_index_array.size() != index_array_size);
+
+ ERR_FAIL_COND(p_blend_shapes.size() != mesh->blend_shape_count);
+
+ for (int i = 0; i < p_blend_shapes.size(); i++) {
+ ERR_FAIL_COND(p_blend_shapes[i].size() != array_size);
+ }
+
+ // all valid, create stuff
+
+ Surface *surface = memnew(Surface);
+
+ surface->active = true;
+ surface->array_len = p_vertex_count;
+ surface->index_array_len = p_index_count;
+ surface->array_byte_size = array.size();
+ surface->index_array_byte_size = p_index_array.size();
+ surface->primitive = p_primitive;
+ surface->mesh = mesh;
+ surface->format = p_format;
+ surface->skeleton_bone_aabb = p_bone_aabbs;
+ surface->skeleton_bone_used.resize(surface->skeleton_bone_aabb.size());
+
+ surface->aabb = p_aabb;
+ surface->max_bone = p_bone_aabbs.size();
+
+ surface->data = array;
+ surface->index_data = p_index_array;
+
+ surface->total_data_size += surface->array_byte_size + surface->index_array_byte_size;
+
+ for (int i = 0; i < surface->skeleton_bone_used.size(); i++) {
+ surface->skeleton_bone_used.write[i] = surface->skeleton_bone_aabb[i].size.x < 0 || surface->skeleton_bone_aabb[i].size.y < 0 || surface->skeleton_bone_aabb[i].size.z < 0;
+ }
+
+ for (int i = 0; i < VS::ARRAY_MAX; i++) {
+ surface->attribs[i] = attribs[i];
+ }
+
+ // Okay, now the OpenGL stuff, wheeeeey \o/
+ {
+ PoolVector<uint8_t>::Read vr = array.read();
+
+ glGenBuffers(1, &surface->vertex_id);
+ glBindBuffer(GL_ARRAY_BUFFER, surface->vertex_id);
+ glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), (p_format & VS::ARRAY_FLAG_USE_DYNAMIC_UPDATE) ? GL_DYNAMIC_DRAW : GL_STATIC_DRAW);
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ if (p_format & VS::ARRAY_FORMAT_INDEX) {
+ PoolVector<uint8_t>::Read ir = p_index_array.read();
+
+ glGenBuffers(1, &surface->index_id);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, surface->index_id);
+ glBufferData(GL_ELEMENT_ARRAY_BUFFER, index_array_size, ir.ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ // TODO generate wireframes
+ }
+
+ {
+ // blend shapes
+
+ for (int i = 0; i < p_blend_shapes.size(); i++) {
+
+ Surface::BlendShape mt;
+
+ PoolVector<uint8_t>::Read vr = p_blend_shapes[i].read();
+
+ surface->total_data_size += array_size;
+
+ glGenBuffers(1, &mt.vertex_id);
+ glBindBuffer(GL_ARRAY_BUFFER, mt.vertex_id);
+ glBufferData(GL_ARRAY_BUFFER, array_size, vr.ptr(), GL_STATIC_DRAW);
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ surface->blend_shapes.push_back(mt);
+ }
+ }
+
+ mesh->surfaces.push_back(surface);
+ mesh->instance_change_notify();
+
+ info.vertex_mem += surface->total_data_size;
}
void RasterizerStorageGLES2::mesh_set_blend_shape_count(RID p_mesh, int p_amount) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ ERR_FAIL_COND(mesh->surfaces.size() != 0);
+ ERR_FAIL_COND(p_amount < 0);
+
+ mesh->blend_shape_count = p_amount;
}
int RasterizerStorageGLES2::mesh_get_blend_shape_count(RID p_mesh) const {
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, 0);
+
+ return mesh->blend_shape_count;
}
void RasterizerStorageGLES2::mesh_set_blend_shape_mode(RID p_mesh, VS::BlendShapeMode p_mode) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ mesh->blend_shape_mode = p_mode;
}
VS::BlendShapeMode RasterizerStorageGLES2::mesh_get_blend_shape_mode(RID p_mesh) const {
- return VS::BLEND_SHAPE_MODE_NORMALIZED;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, VS::BLEND_SHAPE_MODE_NORMALIZED);
+
+ return mesh->blend_shape_mode;
}
void RasterizerStorageGLES2::mesh_surface_update_region(RID p_mesh, int p_surface, int p_offset, const PoolVector<uint8_t> &p_data) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX(p_surface, mesh->surfaces.size());
+
+ int total_size = p_data.size();
+ ERR_FAIL_COND(p_offset + total_size > mesh->surfaces[p_surface]->array_byte_size);
+
+ PoolVector<uint8_t>::Read r = p_data.read();
+
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->vertex_id);
+ glBufferSubData(GL_ARRAY_BUFFER, p_offset, total_size, r.ptr());
+ glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
void RasterizerStorageGLES2::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX(p_surface, mesh->surfaces.size());
+
+ if (mesh->surfaces[p_surface]->material == p_material)
+ return;
+
+ if (mesh->surfaces[p_surface]->material.is_valid()) {
+ _material_remove_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]);
+ }
+
+ mesh->surfaces[p_surface]->material = p_material;
+
+ if (mesh->surfaces[p_surface]->material.is_valid()) {
+ _material_add_geometry(mesh->surfaces[p_surface]->material, mesh->surfaces[p_surface]);
+ }
+
+ mesh->instance_material_change_notify();
}
RID RasterizerStorageGLES2::mesh_surface_get_material(RID p_mesh, int p_surface) const {
- return RID();
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), RID());
+
+ return mesh->surfaces[p_surface]->material;
}
int RasterizerStorageGLES2::mesh_surface_get_array_len(RID p_mesh, int p_surface) const {
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, 0);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0);
+
+ return mesh->surfaces[p_surface]->array_len;
}
int RasterizerStorageGLES2::mesh_surface_get_array_index_len(RID p_mesh, int p_surface) const {
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, 0);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0);
+
+ return mesh->surfaces[p_surface]->index_array_len;
}
PoolVector<uint8_t> RasterizerStorageGLES2::mesh_surface_get_array(RID p_mesh, int p_surface) const {
- return PoolVector<uint8_t>();
+
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, PoolVector<uint8_t>());
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), PoolVector<uint8_t>());
+
+ Surface *surface = mesh->surfaces[p_surface];
+
+ return surface->data;
}
PoolVector<uint8_t> RasterizerStorageGLES2::mesh_surface_get_index_array(RID p_mesh, int p_surface) const {
- return PoolVector<uint8_t>();
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, PoolVector<uint8_t>());
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), PoolVector<uint8_t>());
+
+ Surface *surface = mesh->surfaces[p_surface];
+
+ return surface->index_data;
}
uint32_t RasterizerStorageGLES2::mesh_surface_get_format(RID p_mesh, int p_surface) const {
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+
+ ERR_FAIL_COND_V(!mesh, 0);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), 0);
+
+ return mesh->surfaces[p_surface]->format;
}
VS::PrimitiveType RasterizerStorageGLES2::mesh_surface_get_primitive_type(RID p_mesh, int p_surface) const {
- return VS::PRIMITIVE_TRIANGLES;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, VS::PRIMITIVE_MAX);
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), VS::PRIMITIVE_MAX);
+
+ return mesh->surfaces[p_surface]->primitive;
}
AABB RasterizerStorageGLES2::mesh_surface_get_aabb(RID p_mesh, int p_surface) const {
- return AABB();
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, AABB());
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), AABB());
+
+ return mesh->surfaces[p_surface]->aabb;
}
Vector<PoolVector<uint8_t> > RasterizerStorageGLES2::mesh_surface_get_blend_shapes(RID p_mesh, int p_surface) const {
+ WARN_PRINT("GLES2 mesh_surface_get_blend_shapes is not implemented");
return Vector<PoolVector<uint8_t> >();
}
Vector<AABB> RasterizerStorageGLES2::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const {
- return Vector<AABB>();
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, Vector<AABB>());
+ ERR_FAIL_INDEX_V(p_surface, mesh->surfaces.size(), Vector<AABB>());
+
+ return mesh->surfaces[p_surface]->skeleton_bone_aabb;
}
void RasterizerStorageGLES2::mesh_remove_surface(RID p_mesh, int p_surface) {
+
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+ ERR_FAIL_INDEX(p_surface, mesh->surfaces.size());
+
+ Surface *surface = mesh->surfaces[p_surface];
+
+ if (surface->material.is_valid()) {
+ // TODO _material_remove_geometry(surface->material, mesh->surfaces[p_surface]);
+ }
+
+ glDeleteBuffers(1, &surface->vertex_id);
+ if (surface->index_id) {
+ glDeleteBuffers(1, &surface->index_id);
+ }
+
+ for (int i = 0; i < surface->blend_shapes.size(); i++) {
+ glDeleteBuffers(1, &surface->blend_shapes[i].vertex_id);
+ }
+
+ info.vertex_mem -= surface->total_data_size;
+
+ mesh->instance_material_change_notify();
+
+ memdelete(surface);
+
+ mesh->surfaces.remove(p_surface);
+
+ mesh->instance_change_notify();
}
int RasterizerStorageGLES2::mesh_get_surface_count(RID p_mesh) const {
- return 0;
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, 0);
+ return mesh->surfaces.size();
}
void RasterizerStorageGLES2::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ mesh->custom_aabb = p_aabb;
}
AABB RasterizerStorageGLES2::mesh_get_custom_aabb(RID p_mesh) const {
- return AABB();
+ const Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND_V(!mesh, AABB());
+
+ return mesh->custom_aabb;
}
AABB RasterizerStorageGLES2::mesh_get_aabb(RID p_mesh, RID p_skeleton) const {
- return AABB();
+ Mesh *mesh = mesh_owner.get(p_mesh);
+ ERR_FAIL_COND_V(!mesh, AABB());
+
+ if (mesh->custom_aabb != AABB())
+ return mesh->custom_aabb;
+
+ // TODO handle skeletons
+
+ AABB aabb;
+
+ if (mesh->surfaces.size() >= 1) {
+ aabb = mesh->surfaces[0]->aabb;
+ }
+
+ for (int i = 0; i < mesh->surfaces.size(); i++) {
+ aabb.merge_with(mesh->surfaces[i]->aabb);
+ }
+
+ return aabb;
}
void RasterizerStorageGLES2::mesh_clear(RID p_mesh) {
+ Mesh *mesh = mesh_owner.getornull(p_mesh);
+ ERR_FAIL_COND(!mesh);
+
+ while (mesh->surfaces.size()) {
+ mesh_remove_surface(p_mesh, 0);
+ }
}
/* MULTIMESH API */
RID RasterizerStorageGLES2::multimesh_create() {
- return RID();
+ MultiMesh *multimesh = memnew(MultiMesh);
+ return multimesh_owner.make_rid(multimesh);
}
-void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format) {
+void RasterizerStorageGLES2::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+
+ if (multimesh->size == p_instances && multimesh->transform_format == p_transform_format && multimesh->color_format == p_color_format && multimesh->custom_data_format == p_data) {
+ return;
+ }
+
+ multimesh->size = p_instances;
+
+ multimesh->color_format = p_color_format;
+ multimesh->transform_format = p_transform_format;
+ multimesh->custom_data_format = p_data;
+
+ if (multimesh->size) {
+ multimesh->data.resize(0);
+ }
+
+ if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) {
+ multimesh->xform_floats = 8;
+ } else {
+ multimesh->xform_floats = 12;
+ }
+
+ if (multimesh->color_format == VS::MULTIMESH_COLOR_NONE) {
+ multimesh->color_floats = 0;
+ } else if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ multimesh->color_floats = 1;
+ } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) {
+ multimesh->color_floats = 4;
+ }
+
+ if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE) {
+ multimesh->custom_data_floats = 0;
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ multimesh->custom_data_floats = 1;
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ multimesh->custom_data_floats = 4;
+ }
+
+ int format_floats = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+
+ multimesh->data.resize(format_floats * p_instances);
+
+ 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;
+ 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;
+ color_from = 12;
+ custom_data_from = 12;
+ }
+
+ if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ cu.colu = 0xFFFFFFFF;
+ multimesh->data.write[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;
+ custom_data_from = color_from + 4;
+ }
+
+ if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ cu.colu = 0;
+ multimesh->data.write[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;
+ }
+ }
+
+ multimesh->dirty_aabb = true;
+ multimesh->dirty_data = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
int RasterizerStorageGLES2::multimesh_get_instance_count(RID p_multimesh) const {
- return 0;
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, 0);
+
+ return multimesh->size;
}
void RasterizerStorageGLES2::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+
+ if (multimesh->mesh.is_valid()) {
+ Mesh *mesh = mesh_owner.getornull(multimesh->mesh);
+ if (mesh) {
+ mesh->multimeshes.remove(&multimesh->mesh_list);
+ }
+ }
+
+ multimesh->mesh = p_mesh;
+
+ if (multimesh->mesh.is_valid()) {
+ Mesh *mesh = mesh_owner.getornull(multimesh->mesh);
+ if (mesh) {
+ mesh->multimeshes.add(&multimesh->mesh_list);
+ }
+ }
+
+ multimesh->dirty_aabb = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
void RasterizerStorageGLES2::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->size);
+ ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D);
+
+ int stride = multimesh->color_floats + multimesh->custom_data_floats + multimesh->xform_floats;
+
+ float *dataptr = &multimesh->data.write[stride * p_index];
+
+ dataptr[0] = p_transform.basis.elements[0][0];
+ dataptr[1] = p_transform.basis.elements[0][1];
+ dataptr[2] = p_transform.basis.elements[0][2];
+ dataptr[3] = p_transform.origin.x;
+ dataptr[4] = p_transform.basis.elements[1][0];
+ dataptr[5] = p_transform.basis.elements[1][1];
+ dataptr[6] = p_transform.basis.elements[1][2];
+ dataptr[7] = p_transform.origin.y;
+ dataptr[8] = p_transform.basis.elements[2][0];
+ dataptr[9] = p_transform.basis.elements[2][1];
+ dataptr[10] = p_transform.basis.elements[2][2];
+ dataptr[11] = p_transform.origin.z;
+
+ multimesh->dirty_data = true;
+ multimesh->dirty_aabb = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
void RasterizerStorageGLES2::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->size);
+ ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D);
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index];
+
+ dataptr[0] = p_transform.elements[0][0];
+ dataptr[1] = p_transform.elements[1][0];
+ dataptr[2] = 0;
+ dataptr[3] = p_transform.elements[2][0];
+ dataptr[4] = p_transform.elements[0][1];
+ dataptr[5] = p_transform.elements[1][1];
+ dataptr[6] = 0;
+ dataptr[7] = p_transform.elements[2][1];
+
+ multimesh->dirty_data = true;
+ multimesh->dirty_aabb = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
void RasterizerStorageGLES2::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->size);
+ ERR_FAIL_COND(multimesh->color_format == VS::MULTIMESH_COLOR_NONE);
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats];
+
+ if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+
+ uint8_t *data8 = (uint8_t *)dataptr;
+ data8[0] = CLAMP(p_color.r * 255.0, 0, 255);
+ data8[1] = CLAMP(p_color.g * 255.0, 0, 255);
+ data8[2] = CLAMP(p_color.b * 255.0, 0, 255);
+ data8[3] = CLAMP(p_color.a * 255.0, 0, 255);
+
+ } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) {
+ dataptr[0] = p_color.r;
+ dataptr[1] = p_color.g;
+ dataptr[2] = p_color.b;
+ dataptr[3] = p_color.a;
+ }
+
+ multimesh->dirty_data = true;
+ multimesh->dirty_aabb = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
+}
+
+void RasterizerStorageGLES2::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->size);
+ ERR_FAIL_COND(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE);
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats];
+
+ if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+
+ uint8_t *data8 = (uint8_t *)dataptr;
+ data8[0] = CLAMP(p_custom_data.r * 255.0, 0, 255);
+ data8[1] = CLAMP(p_custom_data.g * 255.0, 0, 255);
+ data8[2] = CLAMP(p_custom_data.b * 255.0, 0, 255);
+ data8[3] = CLAMP(p_custom_data.a * 255.0, 0, 255);
+
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ dataptr[0] = p_custom_data.r;
+ dataptr[1] = p_custom_data.g;
+ dataptr[2] = p_custom_data.b;
+ dataptr[3] = p_custom_data.a;
+ }
+
+ multimesh->dirty_data = true;
+ multimesh->dirty_aabb = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
}
RID RasterizerStorageGLES2::multimesh_get_mesh(RID p_multimesh) const {
- return RID();
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, RID());
+
+ return multimesh->mesh;
}
Transform RasterizerStorageGLES2::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
- return Transform();
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Transform());
+ ERR_FAIL_INDEX_V(p_index, multimesh->size, Transform());
+ ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D, Transform());
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index];
+
+ Transform xform;
+
+ xform.basis.elements[0][0] = dataptr[0];
+ xform.basis.elements[0][1] = dataptr[1];
+ xform.basis.elements[0][2] = dataptr[2];
+ xform.origin.x = dataptr[3];
+ xform.basis.elements[1][0] = dataptr[4];
+ xform.basis.elements[1][1] = dataptr[5];
+ xform.basis.elements[1][2] = dataptr[6];
+ xform.origin.y = dataptr[7];
+ xform.basis.elements[2][0] = dataptr[8];
+ xform.basis.elements[2][1] = dataptr[9];
+ xform.basis.elements[2][2] = dataptr[10];
+ xform.origin.z = dataptr[11];
+
+ return xform;
}
Transform2D RasterizerStorageGLES2::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
- return Transform2D();
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Transform2D());
+ ERR_FAIL_INDEX_V(p_index, multimesh->size, Transform2D());
+ ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D, Transform2D());
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index];
+
+ Transform2D xform;
+
+ xform.elements[0][0] = dataptr[0];
+ xform.elements[1][0] = dataptr[1];
+ xform.elements[2][0] = dataptr[3];
+ xform.elements[0][1] = dataptr[4];
+ xform.elements[1][1] = dataptr[5];
+ xform.elements[2][1] = dataptr[7];
+
+ return xform;
}
Color RasterizerStorageGLES2::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_INDEX_V(p_index, multimesh->size, Color());
+ ERR_FAIL_COND_V(multimesh->color_format == VS::MULTIMESH_COLOR_NONE, Color());
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats];
+
+ if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ cu.colf = dataptr[0];
+
+ return Color::hex(BSWAP32(cu.colu));
+
+ } else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) {
+ Color c;
+ c.r = dataptr[0];
+ c.g = dataptr[1];
+ c.b = dataptr[2];
+ c.a = dataptr[3];
+
+ return c;
+ }
+
+ return Color();
+}
+
+Color RasterizerStorageGLES2::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_INDEX_V(p_index, multimesh->size, Color());
+ ERR_FAIL_COND_V(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE, Color());
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats];
+
+ if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ cu.colf = dataptr[0];
+
+ return Color::hex(BSWAP32(cu.colu));
+
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ Color c;
+ c.r = dataptr[0];
+ c.g = dataptr[1];
+ c.b = dataptr[2];
+ c.a = dataptr[3];
+
+ return c;
+ }
+
return Color();
}
+void RasterizerStorageGLES2::multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+
+ int dsize = multimesh->data.size();
+
+ ERR_FAIL_COND(dsize != p_array.size());
+
+ PoolVector<float>::Read r = p_array.read();
+ copymem(multimesh->data.ptrw(), r.ptr(), dsize * sizeof(float));
+
+ multimesh->dirty_data = true;
+ multimesh->dirty_aabb = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
+}
+
void RasterizerStorageGLES2::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+
+ multimesh->visible_instances = p_visible;
}
int RasterizerStorageGLES2::multimesh_get_visible_instances(RID p_multimesh) const {
- return 0;
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, -1);
+
+ return multimesh->visible_instances;
}
AABB RasterizerStorageGLES2::multimesh_get_aabb(RID p_multimesh) const {
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, AABB());
- return AABB();
+ const_cast<RasterizerStorageGLES2 *>(this)->update_dirty_multimeshes();
+
+ return multimesh->aabb;
}
void RasterizerStorageGLES2::update_dirty_multimeshes() {
+
+ while (multimesh_update_list.first()) {
+
+ MultiMesh *multimesh = multimesh_update_list.first()->self();
+
+ if (multimesh->size && multimesh->dirty_aabb) {
+
+ AABB mesh_aabb;
+
+ if (multimesh->mesh.is_valid()) {
+ mesh_aabb = mesh_get_aabb(multimesh->mesh, RID());
+ } else {
+ mesh_aabb.size += Vector3(0.001, 0.001, 0.001);
+ }
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ int count = multimesh->data.size();
+ float *data = multimesh->data.ptrw();
+
+ AABB aabb;
+
+ if (multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D) {
+
+ for (int i = 0; i < count; i += stride) {
+
+ float *dataptr = &data[i];
+
+ Transform xform;
+ xform.basis[0][0] = dataptr[0];
+ xform.basis[0][1] = dataptr[1];
+ xform.origin[0] = dataptr[3];
+ xform.basis[1][0] = dataptr[4];
+ xform.basis[1][1] = dataptr[5];
+ xform.origin[1] = dataptr[7];
+
+ AABB laabb = xform.xform(mesh_aabb);
+
+ if (i == 0) {
+ aabb = laabb;
+ } else {
+ aabb.merge_with(laabb);
+ }
+ }
+
+ } else {
+
+ for (int i = 0; i < count; i += stride) {
+
+ float *dataptr = &data[i];
+
+ Transform xform;
+ xform.basis.elements[0][0] = dataptr[0];
+ xform.basis.elements[0][1] = dataptr[1];
+ xform.basis.elements[0][2] = dataptr[2];
+ xform.origin.x = dataptr[3];
+ xform.basis.elements[1][0] = dataptr[4];
+ xform.basis.elements[1][1] = dataptr[5];
+ xform.basis.elements[1][2] = dataptr[6];
+ xform.origin.y = dataptr[7];
+ xform.basis.elements[2][0] = dataptr[8];
+ xform.basis.elements[2][1] = dataptr[9];
+ xform.basis.elements[2][2] = dataptr[10];
+ xform.origin.z = dataptr[11];
+
+ AABB laabb = xform.xform(mesh_aabb);
+
+ if (i == 0) {
+ aabb = laabb;
+ } else {
+ aabb.merge_with(laabb);
+ }
+ }
+ }
+
+ multimesh->aabb = aabb;
+ }
+
+ multimesh->dirty_aabb = false;
+ multimesh->dirty_data = false;
+
+ multimesh->instance_change_notify();
+
+ multimesh_update_list.remove(multimesh_update_list.first());
+ }
}
/* IMMEDIATE API */
RID RasterizerStorageGLES2::immediate_create() {
- return RID();
+ Immediate *im = memnew(Immediate);
+ return immediate_owner.make_rid(im);
}
-void RasterizerStorageGLES2::immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture) {
+void RasterizerStorageGLES2::immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(im->building);
+
+ Immediate::Chunk ic;
+ ic.texture = p_texture;
+ ic.primitive = p_primitive;
+ im->chunks.push_back(ic);
+ im->mask = 0;
+ im->building = true;
}
void RasterizerStorageGLES2::immediate_vertex(RID p_immediate, const Vector3 &p_vertex) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(!im->building);
+
+ Immediate::Chunk *c = &im->chunks.back()->get();
+
+ if (c->vertices.empty() && im->chunks.size() == 1) {
+ im->aabb.position = p_vertex;
+ im->aabb.size = Vector3();
+ } else {
+ im->aabb.expand_to(p_vertex);
+ }
+
+ if (im->mask & VS::ARRAY_FORMAT_NORMAL)
+ c->normals.push_back(chunk_normal);
+ if (im->mask & VS::ARRAY_FORMAT_TANGENT)
+ c->tangents.push_back(chunk_tangent);
+ if (im->mask & VS::ARRAY_FORMAT_COLOR)
+ c->colors.push_back(chunk_color);
+ if (im->mask & VS::ARRAY_FORMAT_TEX_UV)
+ c->uvs.push_back(chunk_uv);
+ if (im->mask & VS::ARRAY_FORMAT_TEX_UV2)
+ c->uv2s.push_back(chunk_uv2);
+ im->mask |= VS::ARRAY_FORMAT_VERTEX;
+ c->vertices.push_back(p_vertex);
}
void RasterizerStorageGLES2::immediate_normal(RID p_immediate, const Vector3 &p_normal) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(!im->building);
+
+ im->mask |= VS::ARRAY_FORMAT_NORMAL;
+ chunk_normal = p_normal;
}
void RasterizerStorageGLES2::immediate_tangent(RID p_immediate, const Plane &p_tangent) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(!im->building);
+
+ im->mask |= VS::ARRAY_FORMAT_TANGENT;
+ chunk_tangent = p_tangent;
}
void RasterizerStorageGLES2::immediate_color(RID p_immediate, const Color &p_color) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(!im->building);
+
+ im->mask |= VS::ARRAY_FORMAT_COLOR;
+ chunk_color = p_color;
}
void RasterizerStorageGLES2::immediate_uv(RID p_immediate, const Vector2 &tex_uv) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(!im->building);
+
+ im->mask |= VS::ARRAY_FORMAT_TEX_UV;
+ chunk_uv = tex_uv;
}
void RasterizerStorageGLES2::immediate_uv2(RID p_immediate, const Vector2 &tex_uv) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(!im->building);
+
+ im->mask |= VS::ARRAY_FORMAT_TEX_UV2;
+ chunk_uv2 = tex_uv;
}
void RasterizerStorageGLES2::immediate_end(RID p_immediate) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(!im->building);
+
+ im->building = false;
+ im->instance_change_notify();
}
void RasterizerStorageGLES2::immediate_clear(RID p_immediate) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+ ERR_FAIL_COND(im->building);
+
+ im->chunks.clear();
+ im->instance_change_notify();
}
AABB RasterizerStorageGLES2::immediate_get_aabb(RID p_immediate) const {
- return AABB();
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND_V(!im, AABB());
+ return im->aabb;
}
void RasterizerStorageGLES2::immediate_set_material(RID p_immediate, RID p_material) {
+ Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND(!im);
+
+ im->material = p_material;
+ im->instance_material_change_notify();
}
RID RasterizerStorageGLES2::immediate_get_material(RID p_immediate) const {
- return RID();
+ const Immediate *im = immediate_owner.get(p_immediate);
+ ERR_FAIL_COND_V(!im, RID());
+ return im->material;
}
/* SKELETON API */
RID RasterizerStorageGLES2::skeleton_create() {
- return RID();
+
+ Skeleton *skeleton = memnew(Skeleton);
+
+ return skeleton_owner.make_rid(skeleton);
}
void RasterizerStorageGLES2::skeleton_allocate(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
+
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_COND(p_bones < 0);
+
+ if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton) {
+ return;
+ }
+
+ skeleton->size = p_bones;
+ skeleton->use_2d = p_2d_skeleton;
+
+ // TODO use float texture for vertex shader
+ if (config.float_texture_supported) {
+ glGenTextures(1, &skeleton->tex_id);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, skeleton->tex_id);
+
+#ifdef GLES_OVER_GL
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, p_bones * 3, 1, 0, GL_RGBA, GL_FLOAT, NULL);
+#else
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, p_bones * 3, 1, 0, GL_RGBA, GL_FLOAT, NULL);
+#endif
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
+ if (skeleton->use_2d) {
+ skeleton->bone_data.resize(p_bones * 4 * 2);
+ } else {
+ skeleton->bone_data.resize(p_bones * 4 * 3);
+ }
}
int RasterizerStorageGLES2::skeleton_get_bone_count(RID p_skeleton) const {
- return 0;
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND_V(!skeleton, 0);
+
+ return skeleton->size;
}
void RasterizerStorageGLES2::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform &p_transform) {
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND(!skeleton);
+
+ ERR_FAIL_INDEX(p_bone, skeleton->size);
+ ERR_FAIL_COND(skeleton->use_2d);
+
+ float *bone_data = skeleton->bone_data.ptrw();
+
+ int base_offset = p_bone * 4 * 3;
+
+ bone_data[base_offset + 0] = p_transform.basis[0].x;
+ bone_data[base_offset + 1] = p_transform.basis[0].y;
+ bone_data[base_offset + 2] = p_transform.basis[0].z;
+ bone_data[base_offset + 3] = p_transform.origin.x;
+
+ bone_data[base_offset + 4] = p_transform.basis[1].x;
+ bone_data[base_offset + 5] = p_transform.basis[1].y;
+ bone_data[base_offset + 6] = p_transform.basis[1].z;
+ bone_data[base_offset + 7] = p_transform.origin.y;
+
+ bone_data[base_offset + 8] = p_transform.basis[2].x;
+ bone_data[base_offset + 9] = p_transform.basis[2].y;
+ bone_data[base_offset + 10] = p_transform.basis[2].z;
+ bone_data[base_offset + 11] = p_transform.origin.z;
+
+ if (!skeleton->update_list.in_list()) {
+ skeleton_update_list.add(&skeleton->update_list);
+ }
}
Transform RasterizerStorageGLES2::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
- return Transform();
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND_V(!skeleton, Transform());
+
+ ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform());
+ ERR_FAIL_COND_V(skeleton->use_2d, Transform());
+
+ const float *bone_data = skeleton->bone_data.ptr();
+
+ Transform ret;
+
+ int base_offset = p_bone * 4 * 3;
+
+ ret.basis[0].x = bone_data[base_offset + 0];
+ ret.basis[0].y = bone_data[base_offset + 1];
+ ret.basis[0].z = bone_data[base_offset + 2];
+ ret.origin.x = bone_data[base_offset + 3];
+
+ ret.basis[1].x = bone_data[base_offset + 4];
+ ret.basis[1].y = bone_data[base_offset + 5];
+ ret.basis[1].z = bone_data[base_offset + 6];
+ ret.origin.y = bone_data[base_offset + 7];
+
+ ret.basis[2].x = bone_data[base_offset + 8];
+ ret.basis[2].y = bone_data[base_offset + 9];
+ ret.basis[2].z = bone_data[base_offset + 10];
+ ret.origin.z = bone_data[base_offset + 11];
+
+ return ret;
}
void RasterizerStorageGLES2::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND(!skeleton);
+
+ ERR_FAIL_INDEX(p_bone, skeleton->size);
+ ERR_FAIL_COND(!skeleton->use_2d);
+
+ float *bone_data = skeleton->bone_data.ptrw();
+
+ int base_offset = p_bone * 4 * 2;
+
+ bone_data[base_offset + 0] = p_transform[0][0];
+ bone_data[base_offset + 1] = p_transform[1][0];
+ bone_data[base_offset + 2] = 0;
+ bone_data[base_offset + 3] = p_transform[2][0];
+ bone_data[base_offset + 4] = p_transform[0][1];
+ bone_data[base_offset + 5] = p_transform[1][1];
+ bone_data[base_offset + 6] = 0;
+ bone_data[base_offset + 7] = p_transform[2][1];
+
+ if (!skeleton->update_list.in_list()) {
+ skeleton_update_list.add(&skeleton->update_list);
+ }
}
Transform2D RasterizerStorageGLES2::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
- return Transform2D();
+ Skeleton *skeleton = skeleton_owner.getornull(p_skeleton);
+ ERR_FAIL_COND_V(!skeleton, Transform2D());
+
+ ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D());
+ ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D());
+
+ const float *bone_data = skeleton->bone_data.ptr();
+
+ Transform2D ret;
+
+ int base_offset = p_bone * 4 * 2;
+
+ ret[0][0] = bone_data[base_offset + 0];
+ ret[1][0] = bone_data[base_offset + 1];
+ ret[2][0] = bone_data[base_offset + 3];
+ ret[0][1] = bone_data[base_offset + 4];
+ ret[1][1] = bone_data[base_offset + 5];
+ ret[2][1] = bone_data[base_offset + 7];
+
+ return ret;
}
void RasterizerStorageGLES2::skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform) {
}
+void RasterizerStorageGLES2::_update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size) {
+
+ glBindBuffer(GL_ARRAY_BUFFER, resources.skeleton_transform_buffer);
+
+ if (p_size > resources.skeleton_transform_buffer_size) {
+ // new requested buffer is bigger, so resizing the GPU buffer
+
+ resources.skeleton_transform_buffer_size = p_size;
+
+ glBufferData(GL_ARRAY_BUFFER, p_size * sizeof(float), p_data.read().ptr(), GL_DYNAMIC_DRAW);
+ } else {
+ glBufferSubData(GL_ARRAY_BUFFER, 0, p_size * sizeof(float), p_data.read().ptr());
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+}
+
void RasterizerStorageGLES2::update_dirty_skeletons() {
+
+ if (!config.float_texture_supported)
+ return;
+
+ glActiveTexture(GL_TEXTURE0);
+
+ while (skeleton_update_list.first()) {
+ Skeleton *skeleton = skeleton_update_list.first()->self();
+
+ if (skeleton->size) {
+ glBindTexture(GL_TEXTURE_2D, skeleton->tex_id);
+
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, skeleton->size * 3, 1, GL_RGBA, GL_FLOAT, skeleton->bone_data.ptr());
+ }
+
+ for (Set<RasterizerScene::InstanceBase *>::Element *E = skeleton->instances.front(); E; E = E->next()) {
+ E->get()->base_changed();
+ }
+
+ skeleton_update_list.remove(skeleton_update_list.first());
+ }
}
/* Light API */
RID RasterizerStorageGLES2::light_create(VS::LightType p_type) {
- return RID();
+
+ Light *light = memnew(Light);
+
+ light->type = p_type;
+
+ light->param[VS::LIGHT_PARAM_ENERGY] = 1.0;
+ light->param[VS::LIGHT_PARAM_INDIRECT_ENERGY] = 1.0;
+ light->param[VS::LIGHT_PARAM_SPECULAR] = 0.5;
+ light->param[VS::LIGHT_PARAM_RANGE] = 1.0;
+ light->param[VS::LIGHT_PARAM_SPOT_ANGLE] = 45;
+ light->param[VS::LIGHT_PARAM_CONTACT_SHADOW_SIZE] = 45;
+ light->param[VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE] = 0;
+ light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET] = 0.1;
+ light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET] = 0.3;
+ light->param[VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET] = 0.6;
+ light->param[VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS] = 0.1;
+ light->param[VS::LIGHT_PARAM_SHADOW_BIAS_SPLIT_SCALE] = 0.1;
+
+ light->color = Color(1, 1, 1, 1);
+ light->shadow = false;
+ light->negative = false;
+ light->cull_mask = 0xFFFFFFFF;
+ light->directional_shadow_mode = VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
+ light->omni_shadow_mode = VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
+ light->omni_shadow_detail = VS::LIGHT_OMNI_SHADOW_DETAIL_VERTICAL;
+ light->directional_blend_splits = false;
+ light->directional_range_mode = VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
+ light->reverse_cull = false;
+ light->version = 0;
+
+ return light_owner.make_rid(light);
}
void RasterizerStorageGLES2::light_set_color(RID p_light, const Color &p_color) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->color = p_color;
}
void RasterizerStorageGLES2::light_set_param(RID p_light, VS::LightParam p_param, float p_value) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+ ERR_FAIL_INDEX(p_param, VS::LIGHT_PARAM_MAX);
+
+ switch (p_param) {
+ case VS::LIGHT_PARAM_RANGE:
+ case VS::LIGHT_PARAM_SPOT_ANGLE:
+ case VS::LIGHT_PARAM_SHADOW_MAX_DISTANCE:
+ case VS::LIGHT_PARAM_SHADOW_SPLIT_1_OFFSET:
+ case VS::LIGHT_PARAM_SHADOW_SPLIT_2_OFFSET:
+ case VS::LIGHT_PARAM_SHADOW_SPLIT_3_OFFSET:
+ case VS::LIGHT_PARAM_SHADOW_NORMAL_BIAS:
+ case VS::LIGHT_PARAM_SHADOW_BIAS: {
+ light->version++;
+ light->instance_change_notify();
+ } break;
+ }
+
+ light->param[p_param] = p_value;
}
void RasterizerStorageGLES2::light_set_shadow(RID p_light, bool p_enabled) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->shadow = p_enabled;
+
+ light->version++;
+ light->instance_change_notify();
}
void RasterizerStorageGLES2::light_set_shadow_color(RID p_light, const Color &p_color) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->shadow_color = p_color;
}
void RasterizerStorageGLES2::light_set_projector(RID p_light, RID p_texture) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->projector = p_texture;
}
void RasterizerStorageGLES2::light_set_negative(RID p_light, bool p_enable) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->negative = p_enable;
}
void RasterizerStorageGLES2::light_set_cull_mask(RID p_light, uint32_t p_mask) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->cull_mask = p_mask;
+
+ light->version++;
+ light->instance_change_notify();
}
void RasterizerStorageGLES2::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->reverse_cull = p_enabled;
}
void RasterizerStorageGLES2::light_omni_set_shadow_mode(RID p_light, VS::LightOmniShadowMode p_mode) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->omni_shadow_mode = p_mode;
+
+ light->version++;
+ light->instance_change_notify();
}
VS::LightOmniShadowMode RasterizerStorageGLES2::light_omni_get_shadow_mode(RID p_light) {
- return VS::LIGHT_OMNI_SHADOW_DUAL_PARABOLOID;
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, VS::LIGHT_OMNI_SHADOW_CUBE);
+
+ return light->omni_shadow_mode;
}
void RasterizerStorageGLES2::light_omni_set_shadow_detail(RID p_light, VS::LightOmniShadowDetail p_detail) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->omni_shadow_detail = p_detail;
+
+ light->version++;
+ light->instance_change_notify();
}
void RasterizerStorageGLES2::light_directional_set_shadow_mode(RID p_light, VS::LightDirectionalShadowMode p_mode) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_shadow_mode = p_mode;
+
+ light->version++;
+ light->instance_change_notify();
}
void RasterizerStorageGLES2::light_directional_set_blend_splits(RID p_light, bool p_enable) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_blend_splits = p_enable;
+
+ light->version++;
+ light->instance_change_notify();
}
bool RasterizerStorageGLES2::light_directional_get_blend_splits(RID p_light) const {
- return false;
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, false);
+ return light->directional_blend_splits;
}
VS::LightDirectionalShadowMode RasterizerStorageGLES2::light_directional_get_shadow_mode(RID p_light) {
- return VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL;
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+ return light->directional_shadow_mode;
}
void RasterizerStorageGLES2::light_directional_set_shadow_depth_range_mode(RID p_light, VS::LightDirectionalShadowDepthRangeMode p_range_mode) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND(!light);
+
+ light->directional_range_mode = p_range_mode;
}
VS::LightDirectionalShadowDepthRangeMode RasterizerStorageGLES2::light_directional_get_shadow_depth_range_mode(RID p_light) const {
- return VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE;
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL_SHADOW_DEPTH_RANGE_STABLE);
+
+ return light->directional_range_mode;
}
VS::LightType RasterizerStorageGLES2::light_get_type(RID p_light) const {
- return VS::LIGHT_DIRECTIONAL;
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, VS::LIGHT_DIRECTIONAL);
+
+ return light->type;
}
float RasterizerStorageGLES2::light_get_param(RID p_light, VS::LightParam p_param) {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, 0.0);
+ ERR_FAIL_INDEX_V(p_param, VS::LIGHT_PARAM_MAX, 0.0);
- return VS::LIGHT_DIRECTIONAL;
+ return light->param[p_param];
}
Color RasterizerStorageGLES2::light_get_color(RID p_light) {
- return Color();
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, Color());
+
+ return light->color;
}
bool RasterizerStorageGLES2::light_has_shadow(RID p_light) const {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, false);
- return VS::LIGHT_DIRECTIONAL;
+ return light->shadow;
}
uint64_t RasterizerStorageGLES2::light_get_version(RID p_light) const {
- return 0;
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, 0);
+
+ return light->version;
}
AABB RasterizerStorageGLES2::light_get_aabb(RID p_light) const {
+ Light *light = light_owner.getornull(p_light);
+ ERR_FAIL_COND_V(!light, AABB());
+
+ switch (light->type) {
+
+ case VS::LIGHT_SPOT: {
+ float len = light->param[VS::LIGHT_PARAM_RANGE];
+ float size = Math::tan(Math::deg2rad(light->param[VS::LIGHT_PARAM_SPOT_ANGLE])) * len;
+ return AABB(Vector3(-size, -size, -len), Vector3(size * 2, size * 2, len));
+ } break;
+
+ case VS::LIGHT_OMNI: {
+ float r = light->param[VS::LIGHT_PARAM_RANGE];
+ return AABB(-Vector3(r, r, r), Vector3(r, r, r) * 2);
+ } break;
+
+ case VS::LIGHT_DIRECTIONAL: {
+ return AABB();
+ } break;
+ }
+
+ ERR_FAIL_V(AABB());
return AABB();
}
@@ -1776,6 +3666,9 @@ void RasterizerStorageGLES2::_render_target_allocate(RenderTarget *rt) {
texture_set_flags(rt->texture, texture->flags);
+ glClearColor(0, 0, 0, 0);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
// copy texscreen buffers
{
int w = rt->width;
@@ -1849,6 +3742,7 @@ RID RasterizerStorageGLES2::render_target_create() {
t->data_size = 0;
t->total_data_size = 0;
t->ignore_mipmaps = false;
+ t->compressed = false;
t->mipmaps = 1;
t->active = true;
t->tex_id = 0;
@@ -1945,14 +3839,205 @@ void RasterizerStorageGLES2::canvas_light_occluder_set_polylines(RID p_occluder,
}
VS::InstanceType RasterizerStorageGLES2::get_base_type(RID p_rid) const {
- return VS::INSTANCE_NONE;
+
+ if (mesh_owner.owns(p_rid)) {
+ return VS::INSTANCE_MESH;
+ } else if (light_owner.owns(p_rid)) {
+ return VS::INSTANCE_LIGHT;
+ } else if (multimesh_owner.owns(p_rid)) {
+ return VS::INSTANCE_MULTIMESH;
+ } else if (immediate_owner.owns(p_rid)) {
+ return VS::INSTANCE_IMMEDIATE;
+ } else {
+ return VS::INSTANCE_NONE;
+ }
}
bool RasterizerStorageGLES2::free(RID p_rid) {
- return false;
+
+ if (render_target_owner.owns(p_rid)) {
+
+ RenderTarget *rt = render_target_owner.getornull(p_rid);
+ _render_target_clear(rt);
+
+ Texture *t = texture_owner.get(rt->texture);
+ texture_owner.free(rt->texture);
+ memdelete(t);
+ render_target_owner.free(p_rid);
+ memdelete(rt);
+
+ return true;
+ } else if (texture_owner.owns(p_rid)) {
+
+ Texture *t = texture_owner.get(p_rid);
+ // can't free a render target texture
+ ERR_FAIL_COND_V(t->render_target, true);
+
+ info.texture_mem -= t->total_data_size;
+ texture_owner.free(p_rid);
+ memdelete(t);
+
+ return true;
+ } else if (sky_owner.owns(p_rid)) {
+
+ Sky *sky = sky_owner.get(p_rid);
+ sky_set_texture(p_rid, RID(), 256);
+ sky_owner.free(p_rid);
+ memdelete(sky);
+
+ return true;
+ } else if (shader_owner.owns(p_rid)) {
+
+ Shader *shader = shader_owner.get(p_rid);
+
+ if (shader->shader) {
+ shader->shader->free_custom_shader(shader->custom_code_id);
+ }
+
+ if (shader->dirty_list.in_list()) {
+ _shader_dirty_list.remove(&shader->dirty_list);
+ }
+
+ while (shader->materials.first()) {
+ Material *m = shader->materials.first()->self();
+
+ m->shader = NULL;
+ _material_make_dirty(m);
+
+ shader->materials.remove(shader->materials.first());
+ }
+
+ shader_owner.free(p_rid);
+ memdelete(shader);
+
+ return true;
+ } else if (material_owner.owns(p_rid)) {
+
+ Material *m = material_owner.get(p_rid);
+
+ if (m->shader) {
+ m->shader->materials.remove(&m->list);
+ }
+
+ for (Map<Geometry *, int>::Element *E = m->geometry_owners.front(); E; E = E->next()) {
+ Geometry *g = E->key();
+ g->material = RID();
+ }
+
+ for (Map<RasterizerScene::InstanceBase *, int>::Element *E = m->instance_owners.front(); E; E = E->next()) {
+
+ RasterizerScene::InstanceBase *ins = E->key();
+
+ if (ins->material_override == p_rid) {
+ ins->material_override = RID();
+ }
+
+ for (int i = 0; i < ins->materials.size(); i++) {
+ if (ins->materials[i] == p_rid) {
+ ins->materials.write[i] = RID();
+ }
+ }
+ }
+
+ material_owner.free(p_rid);
+ memdelete(m);
+
+ return true;
+ } else if (skeleton_owner.owns(p_rid)) {
+
+ Skeleton *s = skeleton_owner.get(p_rid);
+
+ if (s->update_list.in_list()) {
+ skeleton_update_list.remove(&s->update_list);
+ }
+
+ for (Set<RasterizerScene::InstanceBase *>::Element *E = s->instances.front(); E; E = E->next()) {
+ E->get()->skeleton = RID();
+ }
+
+ skeleton_allocate(p_rid, 0, false);
+
+ if (s->tex_id) {
+ glDeleteTextures(1, &s->tex_id);
+ }
+
+ skeleton_owner.free(p_rid);
+ memdelete(s);
+
+ return true;
+ } else if (mesh_owner.owns(p_rid)) {
+
+ Mesh *mesh = mesh_owner.get(p_rid);
+
+ mesh->instance_remove_deps();
+ mesh_clear(p_rid);
+
+ while (mesh->multimeshes.first()) {
+ MultiMesh *multimesh = mesh->multimeshes.first()->self();
+ multimesh->mesh = RID();
+ multimesh->dirty_aabb = true;
+
+ mesh->multimeshes.remove(mesh->multimeshes.first());
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
+ }
+
+ mesh_owner.free(p_rid);
+ memdelete(mesh);
+
+ return true;
+ } else if (multimesh_owner.owns(p_rid)) {
+
+ MultiMesh *multimesh = multimesh_owner.get(p_rid);
+ multimesh->instance_remove_deps();
+
+ if (multimesh->mesh.is_valid()) {
+ Mesh *mesh = mesh_owner.getornull(multimesh->mesh);
+ if (mesh) {
+ mesh->multimeshes.remove(&multimesh->mesh_list);
+ }
+ }
+
+ multimesh_allocate(p_rid, 0, VS::MULTIMESH_TRANSFORM_3D, VS::MULTIMESH_COLOR_NONE);
+
+ update_dirty_multimeshes();
+
+ multimesh_owner.free(p_rid);
+ memdelete(multimesh);
+
+ return true;
+ } else if (immediate_owner.owns(p_rid)) {
+ Immediate *im = immediate_owner.get(p_rid);
+ im->instance_remove_deps();
+
+ immediate_owner.free(p_rid);
+ memdelete(im);
+
+ return true;
+ } else if (light_owner.owns(p_rid)) {
+
+ Light *light = light_owner.get(p_rid);
+ light->instance_remove_deps();
+
+ light_owner.free(p_rid);
+ memdelete(light);
+
+ return true;
+ } else {
+ return false;
+ }
}
bool RasterizerStorageGLES2::has_os_feature(const String &p_feature) const {
+
+ if (p_feature == "s3tc")
+ return config.s3tc_supported;
+
+ if (p_feature == "etc")
+ return config.etc1_supported;
+
return false;
}
@@ -1980,24 +4065,63 @@ void RasterizerStorageGLES2::initialize() {
RasterizerStorageGLES2::system_fbo = 0;
{
- const char *gl_extensions = (const char *)glGetString(GL_EXTENSIONS);
- Vector<String> strings = String(gl_extensions).split(" ", false);
- for (int i = 0; i < strings.size(); i++) {
- config.extensions.insert(strings[i]);
+
+ const GLubyte *extension_string = glGetString(GL_EXTENSIONS);
+
+ Vector<String> extensions = String((const char *)extension_string).split(" ");
+
+ for (int i = 0; i < extensions.size(); i++) {
+ config.extensions.insert(extensions[i]);
}
}
+ 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;
+
frame.count = 0;
- frame.prev_tick = 0;
frame.delta = 0;
frame.current_rt = NULL;
frame.clear_request = false;
// config.keep_original_textures = false;
- glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units);
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units);
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &config.max_texture_size);
shaders.copy.init();
+ shaders.cubemap_filter.init();
+
+ {
+ // quad for copying stuff
+
+ glGenBuffers(1, &resources.quadie);
+ glBindBuffer(GL_ARRAY_BUFFER, resources.quadie);
+ {
+ const float qv[16] = {
+ -1,
+ -1,
+ 0,
+ 0,
+ -1,
+ 1,
+ 0,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ 1,
+ -1,
+ 1,
+ 0,
+ };
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 16, qv, GL_STATIC_DRAW);
+ }
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+ }
{
//default textures
@@ -2054,14 +4178,55 @@ void RasterizerStorageGLES2::initialize() {
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
}
+
+ // skeleton buffer
+ {
+ resources.skeleton_transform_buffer_size = 0;
+ glGenBuffers(1, &resources.skeleton_transform_buffer);
+ }
+
+ // radical inverse vdc cache texture
+ // used for cubemap filtering
+ if (config.float_texture_supported) {
+ 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];
+
+ for (uint32_t i = 0; i < 512; i++) {
+ uint32_t bits = i;
+
+ bits = (bits << 16) | (bits >> 16);
+ bits = ((bits & 0x55555555) << 1) | ((bits & 0xAAAAAAAA) >> 1);
+ bits = ((bits & 0x33333333) << 2) | ((bits & 0xCCCCCCCC) >> 2);
+ bits = ((bits & 0x0F0F0F0F) << 4) | ((bits & 0xF0F0F0F0) >> 4);
+ bits = ((bits & 0x00FF00FF) << 8) | ((bits & 0xFF00FF00) >> 8);
+
+ float value = float(bits) * 2.3283064365386963e-10;
+
+ radical_inverse[i] = value;
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, 512, 1, 0, GL_LUMINANCE, GL_FLOAT, radical_inverse);
+
+ glBindTexture(GL_TEXTURE_2D, 0);
+ }
}
void RasterizerStorageGLES2::finalize() {
}
+void RasterizerStorageGLES2::_copy_screen() {
+ bind_quad_array();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+}
+
void RasterizerStorageGLES2::update_dirty_resources() {
update_dirty_shaders();
update_dirty_materials();
+ update_dirty_skeletons();
}
RasterizerStorageGLES2::RasterizerStorageGLES2() {
diff --git a/drivers/gles2/rasterizer_storage_gles2.h b/drivers/gles2/rasterizer_storage_gles2.h
index b735f2e148..88783d7160 100644
--- a/drivers/gles2/rasterizer_storage_gles2.h
+++ b/drivers/gles2/rasterizer_storage_gles2.h
@@ -30,6 +30,7 @@
#ifndef RASTERIZERSTORAGEGLES2_H
#define RASTERIZERSTORAGEGLES2_H
+#include "dvector.h"
#include "self_list.h"
#include "servers/visual/rasterizer.h"
#include "servers/visual/shader_language.h"
@@ -37,11 +38,11 @@
#include "shader_gles2.h"
#include "shaders/copy.glsl.gen.h"
+#include "shaders/cubemap_filter.glsl.gen.h"
/*
#include "shaders/blend_shape.glsl.gen.h"
#include "shaders/canvas.glsl.gen.h"
#include "shaders/copy.glsl.gen.h"
-#include "shaders/cubemap_filter.glsl.gen.h"
#include "shaders/particles.glsl.gen.h"
*/
@@ -76,6 +77,10 @@ public:
Set<String> extensions;
+ bool float_texture_supported;
+ bool s3tc_supported;
+ bool etc1_supported;
+
bool keep_original_textures;
bool no_depth_prepass;
@@ -89,8 +94,13 @@ public:
GLuint normal_tex;
GLuint aniso_tex;
+ GLuint radical_inverse_vdc_cache_tex;
+
GLuint quadie;
- GLuint quadie_array;
+
+ size_t skeleton_transform_buffer_size;
+ GLuint skeleton_transform_buffer;
+ PoolVector<float> skeleton_transform_cpu_buffer;
} resources;
@@ -99,6 +109,7 @@ public:
ShaderCompilerGLES2 compiler;
CopyShaderGLES2 copy;
+ CubemapFilterShaderGLES2 cubemap_filter;
ShaderCompilerGLES2::IdentifierActions actions_canvas;
ShaderCompilerGLES2::IdentifierActions actions_scene;
@@ -139,10 +150,72 @@ public:
} info;
+ void bind_quad_array() const;
+
/////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////DATA///////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
+ struct Instanciable : public RID_Data {
+ SelfList<RasterizerScene::InstanceBase>::List instance_list;
+
+ _FORCE_INLINE_ void instance_change_notify() {
+ 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 = instances->next();
+ }
+ }
+
+ _FORCE_INLINE_ void instance_remove_deps() {
+ SelfList<RasterizerScene::InstanceBase> *instances = instance_list.first();
+
+ while (instances) {
+ instances->self()->base_removed();
+ instances = instances->next();
+ }
+ }
+
+ Instanciable() {}
+
+ virtual ~Instanciable() {}
+ };
+
+ struct GeometryOwner : public Instanciable {
+ };
+
+ struct Geometry : public Instanciable {
+
+ enum Type {
+ GEOMETRY_INVALID,
+ GEOMETRY_SURFACE,
+ GEOMETRY_IMMEDIATE,
+ GEOMETRY_MULTISURFACE
+ };
+
+ Type type;
+ RID material;
+ uint64_t last_pass;
+ uint32_t index;
+
+ virtual void material_changed_notify() {}
+
+ Geometry() {
+ last_pass = 0;
+ index = 0;
+ }
+ };
+
/////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////API////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////
@@ -158,9 +231,10 @@ public:
String path;
uint32_t flags;
- int width, height;
+ int width, height, depth;
int alloc_width, alloc_height;
Image::Format format;
+ VS::TextureType type;
GLenum target;
GLenum gl_format_cache;
@@ -171,6 +245,10 @@ public:
int total_data_size;
bool ignore_mipmaps;
+ bool compressed;
+
+ bool srgb;
+
int mipmaps;
bool active;
@@ -180,7 +258,18 @@ public:
RenderTarget *render_target;
- Ref<Image> images[6];
+ Vector<Ref<Image> > images;
+
+ bool redraw_if_visible;
+
+ VisualServer::TextureDetectCallback detect_3d;
+ void *detect_3d_ud;
+
+ VisualServer::TextureDetectCallback detect_srgb;
+ void *detect_srgb_ud;
+
+ VisualServer::TextureDetectCallback detect_normal;
+ void *detect_normal_ud;
Texture() {
flags = 0;
@@ -196,6 +285,8 @@ public:
total_data_size = 0;
ignore_mipmaps = false;
+ compressed = false;
+
active = false;
tex_id = 0;
@@ -205,6 +296,8 @@ public:
proxy = NULL;
render_target = NULL;
+
+ redraw_if_visible = false;
}
_ALWAYS_INLINE_ Texture *get_ptr() {
@@ -232,20 +325,22 @@ public:
mutable RID_Owner<Texture> texture_owner;
- Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type);
+ Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed) const;
virtual RID texture_create();
- virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
- virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
- virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
- virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const;
+ virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
+ virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
+ virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0);
+ virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
virtual void texture_set_flags(RID p_texture, uint32_t p_flags);
virtual uint32_t texture_get_flags(RID p_texture) const;
virtual Image::Format texture_get_format(RID p_texture) const;
+ virtual VS::TextureType texture_get_type(RID p_texture) const;
virtual uint32_t texture_get_texid(RID p_texture) const;
virtual uint32_t texture_get_width(RID p_texture) const;
virtual uint32_t texture_get_height(RID p_texture) const;
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height);
+ virtual uint32_t texture_get_depth(RID p_texture) const;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth);
virtual void texture_set_path(RID p_texture, const String &p_path);
virtual String texture_get_path(RID p_texture) const;
@@ -264,8 +359,19 @@ public:
virtual void texture_set_detect_srgb_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
virtual void texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
+ virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable);
+
/* SKY API */
+ struct Sky : public RID_Data {
+
+ RID panorama;
+ GLuint radiance;
+ int radiance_size;
+ };
+
+ mutable RID_Owner<Sky> sky_owner;
+
virtual RID sky_create();
virtual void sky_set_texture(RID p_sky, RID p_panorama, int p_radiance_size);
@@ -326,7 +432,6 @@ public:
} canvas_item;
- /*
struct Spatial {
enum BlendMode {
@@ -363,6 +468,7 @@ public:
bool uses_discard;
bool uses_sss;
bool uses_screen_texture;
+ bool uses_depth_texture;
bool uses_time;
bool writes_modelview_or_projection;
bool uses_vertex_lighting;
@@ -373,7 +479,6 @@ public:
struct Particles {
} particles;
- */
bool uses_vertex_time;
bool uses_fragment_time;
@@ -413,7 +518,7 @@ public:
Map<StringName, Variant> params;
SelfList<Material> list;
SelfList<Material> dirty_list;
- Vector<RID> textures;
+ Vector<Pair<StringName, RID> > textures;
float line_width;
int render_priority;
@@ -443,6 +548,11 @@ public:
mutable SelfList<Material>::List _material_dirty_list;
void _material_make_dirty(Material *p_material) const;
+ void _material_add_geometry(RID p_material, Geometry *p_geometry);
+ void _material_remove_geometry(RID p_material, Geometry *p_geometry);
+
+ void _update_material(Material *p_material);
+
mutable RID_Owner<Material> material_owner;
virtual RID material_create();
@@ -467,6 +577,109 @@ public:
void update_dirty_materials();
/* MESH API */
+
+ struct Mesh;
+
+ struct Surface : public Geometry {
+
+ struct Attrib {
+ bool enabled;
+ bool integer;
+ GLuint index;
+ GLint size;
+ GLenum type;
+ GLboolean normalized;
+ GLsizei stride;
+ uint32_t offset;
+ };
+
+ Attrib attribs[VS::ARRAY_MAX];
+
+ Mesh *mesh;
+ uint32_t format;
+
+ GLuint vertex_id;
+ GLuint index_id;
+
+ struct BlendShape {
+ GLuint vertex_id;
+ GLuint array_id;
+ };
+
+ Vector<BlendShape> blend_shapes;
+
+ AABB aabb;
+
+ int array_len;
+ int index_array_len;
+ int max_bone;
+
+ int array_byte_size;
+ int index_array_byte_size;
+
+ VS::PrimitiveType primitive;
+
+ Vector<AABB> skeleton_bone_aabb;
+ Vector<bool> skeleton_bone_used;
+
+ bool active;
+
+ PoolVector<uint8_t> data;
+ PoolVector<uint8_t> index_data;
+
+ int total_data_size;
+
+ Surface() {
+ array_byte_size = 0;
+ index_array_byte_size = 0;
+
+ array_len = 0;
+ index_array_len = 0;
+
+ mesh = NULL;
+
+ primitive = VS::PRIMITIVE_POINTS;
+
+ active = false;
+
+ total_data_size = 0;
+ }
+ };
+
+ struct MultiMesh;
+
+ struct Mesh : public GeometryOwner {
+
+ bool active;
+
+ Vector<Surface *> surfaces;
+
+ int blend_shape_count;
+ VS::BlendShapeMode blend_shape_mode;
+
+ AABB custom_aabb;
+
+ mutable uint64_t last_pass;
+
+ SelfList<MultiMesh>::List multimeshes;
+
+ _FORCE_INLINE_ void update_multimeshes() {
+ SelfList<MultiMesh> *mm = multimeshes.first();
+
+ while (mm) {
+ mm->self()->instance_material_change_notify();
+ mm = mm->next();
+ }
+ }
+
+ Mesh() {
+ blend_shape_mode = VS::BLEND_SHAPE_MODE_NORMALIZED;
+ blend_shape_count = 0;
+ }
+ };
+
+ mutable RID_Owner<Mesh> mesh_owner;
+
virtual RID mesh_create();
virtual void mesh_add_surface(RID p_mesh, uint32_t p_format, VS::PrimitiveType p_primitive, const PoolVector<uint8_t> &p_array, int p_vertex_count, const PoolVector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<PoolVector<uint8_t> > &p_blend_shapes = Vector<PoolVector<uint8_t> >(), const Vector<AABB> &p_bone_aabbs = Vector<AABB>());
@@ -506,21 +719,74 @@ public:
/* MULTIMESH API */
+ struct MultiMesh : public GeometryOwner {
+
+ RID mesh;
+ int size;
+
+ VS::MultimeshTransformFormat transform_format;
+ VS::MultimeshColorFormat color_format;
+ VS::MultimeshCustomDataFormat custom_data_format;
+
+ Vector<float> data;
+
+ AABB aabb;
+
+ SelfList<MultiMesh> update_list;
+ SelfList<MultiMesh> mesh_list;
+
+ int visible_instances;
+
+ int xform_floats;
+ int color_floats;
+ int custom_data_floats;
+
+ bool dirty_aabb;
+ bool dirty_data;
+
+ MultiMesh() :
+ update_list(this),
+ mesh_list(this) {
+ dirty_aabb = true;
+ dirty_data = true;
+
+ xform_floats = 0;
+ color_floats = 0;
+ custom_data_floats = 0;
+
+ visible_instances = -1;
+
+ size = 0;
+
+ transform_format = VS::MULTIMESH_TRANSFORM_2D;
+ color_format = VS::MULTIMESH_COLOR_NONE;
+ custom_data_format = VS::MULTIMESH_CUSTOM_DATA_NONE;
+ }
+ };
+
+ mutable RID_Owner<MultiMesh> multimesh_owner;
+
+ SelfList<MultiMesh>::List multimesh_update_list;
+
virtual RID multimesh_create();
- virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format);
+ virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data = VS::MULTIMESH_CUSTOM_DATA_NONE);
virtual int multimesh_get_instance_count(RID p_multimesh) const;
virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform);
virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
+ virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data);
virtual RID multimesh_get_mesh(RID p_multimesh) const;
virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const;
virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const;
+ virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
+
+ virtual void multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array);
virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible);
virtual int multimesh_get_visible_instances(RID p_multimesh) const;
@@ -531,8 +797,40 @@ public:
/* IMMEDIATE API */
+ struct Immediate : public Geometry {
+
+ struct Chunk {
+ RID texture;
+ VS::PrimitiveType primitive;
+ Vector<Vector3> vertices;
+ Vector<Vector3> normals;
+ Vector<Plane> tangents;
+ Vector<Color> colors;
+ Vector<Vector2> uvs;
+ Vector<Vector2> uv2s;
+ };
+
+ List<Chunk> chunks;
+ bool building;
+ int mask;
+ AABB aabb;
+
+ Immediate() {
+ type = GEOMETRY_IMMEDIATE;
+ building = false;
+ }
+ };
+
+ Vector3 chunk_normal;
+ Plane chunk_tangent;
+ Color chunk_color;
+ Vector2 chunk_uv;
+ Vector2 chunk_uv2;
+
+ mutable RID_Owner<Immediate> immediate_owner;
+
virtual RID immediate_create();
- virtual void immediate_begin(RID p_immediate, VS::PrimitiveType p_rimitive, RID p_texture = RID());
+ virtual void immediate_begin(RID p_immediate, VS::PrimitiveType p_primitive, RID p_texture = RID());
virtual void immediate_vertex(RID p_immediate, const Vector3 &p_vertex);
virtual void immediate_normal(RID p_immediate, const Vector3 &p_normal);
virtual void immediate_tangent(RID p_immediate, const Plane &p_tangent);
@@ -547,6 +845,33 @@ public:
/* SKELETON API */
+ struct Skeleton : RID_Data {
+
+ bool use_2d;
+
+ int size;
+
+ // TODO use float textures for storage
+
+ Vector<float> bone_data;
+
+ GLuint tex_id;
+
+ SelfList<Skeleton> update_list;
+ Set<RasterizerScene::InstanceBase *> instances;
+
+ Skeleton() :
+ update_list(this) {
+ tex_id = 0;
+ size = 0;
+ use_2d = false;
+ }
+ };
+
+ mutable RID_Owner<Skeleton> skeleton_owner;
+
+ SelfList<Skeleton>::List skeleton_update_list;
+
void update_dirty_skeletons();
virtual RID skeleton_create();
@@ -558,8 +883,38 @@ public:
virtual Transform2D skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const;
virtual void skeleton_set_base_transform_2d(RID p_skeleton, const Transform2D &p_base_transform);
+ void _update_skeleton_transform_buffer(const PoolVector<float> &p_data, size_t p_size);
+
/* Light API */
+ struct Light : Instanciable {
+ VS::LightType type;
+ float param[VS::LIGHT_PARAM_MAX];
+
+ Color color;
+ Color shadow_color;
+
+ RID projector;
+
+ bool shadow;
+ bool negative;
+ bool reverse_cull;
+
+ uint32_t cull_mask;
+
+ VS::LightOmniShadowMode omni_shadow_mode;
+ VS::LightOmniShadowDetail omni_shadow_detail;
+
+ VS::LightDirectionalShadowMode directional_shadow_mode;
+ VS::LightDirectionalShadowDepthRangeMode directional_range_mode;
+
+ bool directional_blend_splits;
+
+ uint64_t version;
+ };
+
+ mutable RID_Owner<Light> light_owner;
+
virtual RID light_create(VS::LightType p_type);
virtual void light_set_color(RID p_light, const Color &p_color);
@@ -814,7 +1169,6 @@ public:
int canvas_draw_commands;
float time[4];
float delta;
- uint64_t prev_tick;
uint64_t count;
} frame;
@@ -822,6 +1176,8 @@ public:
void initialize();
void finalize();
+ void _copy_screen();
+
virtual bool has_os_feature(const String &p_feature) const;
virtual void update_dirty_resources();
diff --git a/drivers/gles2/shader_compiler_gles2.cpp b/drivers/gles2/shader_compiler_gles2.cpp
index aa55e72083..1c87b3ffb5 100644
--- a/drivers/gles2/shader_compiler_gles2.cpp
+++ b/drivers/gles2/shader_compiler_gles2.cpp
@@ -161,7 +161,7 @@ static String get_constant_text(SL::DataType p_type, const Vector<SL::ConstantNo
return text.as_string();
} 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: {
@@ -325,10 +325,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
uniform_code += ";\n";
if (SL::is_sampler_type(E->get().type)) {
- r_gen_code.texture_uniforms[E->get().texture_order] = _mkid(E->key());
- r_gen_code.texture_hints[E->get().texture_order] = E->get().hint;
+ r_gen_code.texture_uniforms.write[E->get().texture_order] = E->key();
+ r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint;
} else {
- r_gen_code.uniforms[E->get().order] = E->key();
+ r_gen_code.uniforms.write[E->get().order] = E->key();
}
vertex_global += uniform_code.as_string();
@@ -507,7 +507,6 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
case SL::OP_ASSIGN_DIV:
case SL::OP_ASSIGN_SHIFT_LEFT:
case SL::OP_ASSIGN_SHIFT_RIGHT:
- case SL::OP_ASSIGN_MOD:
case SL::OP_ASSIGN_BIT_AND:
case SL::OP_ASSIGN_BIT_OR:
case SL::OP_ASSIGN_BIT_XOR: {
@@ -518,6 +517,16 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
} break;
+ case SL::OP_ASSIGN_MOD: {
+ code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true);
+ code += " = ";
+ code += "mod(";
+ code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, true);
+ code += ", ";
+ code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += ")";
+ } break;
+
case SL::OP_BIT_INVERT:
case SL::OP_NEGATE:
case SL::OP_NOT:
@@ -552,6 +561,46 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
code += "textureCube";
}
+ } else if (var_node->name == "textureLod") {
+ // emit texture call
+
+ if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLER2D) {
+ code += "texture2DLod";
+ } else if (op_node->arguments[1]->get_datatype() == SL::TYPE_SAMPLERCUBE) {
+ code += "textureCubeLod";
+ }
+
+ } else if (var_node->name == "mix") {
+
+ switch (op_node->arguments[3]->get_datatype()) {
+
+ case SL::TYPE_BVEC2: {
+ code += "select2";
+ } break;
+
+ case SL::TYPE_BVEC3: {
+ code += "select3";
+ } break;
+
+ case SL::TYPE_BVEC4: {
+ code += "select4";
+ } break;
+
+ case SL::TYPE_VEC2:
+ case SL::TYPE_VEC3:
+ case SL::TYPE_VEC4:
+ case SL::TYPE_FLOAT: {
+
+ code += "mix";
+ } break;
+
+ default: {
+ SL::DataType type = op_node->arguments[3]->get_datatype();
+ // FIXME: Proper error print or graceful handling
+ print_line(String("uhhhh invalid mix with type: ") + itos(type));
+ } break;
+ }
+
} else if (p_default_actions.renames.has(var_node->name)) {
code += p_default_actions.renames[var_node->name];
} else if (internal_functions.has(var_node->name)) {
@@ -590,6 +639,15 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
code += _dump_node_code(op_node->arguments[2], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
} break;
+ case SL::OP_MOD: {
+
+ code += "mod(";
+ code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += ", ";
+ code += _dump_node_code(op_node->arguments[1], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
+ code += ")";
+ } break;
+
default: {
code += "(";
code += _dump_node_code(op_node->arguments[0], p_level, r_gen_code, p_actions, p_default_actions, p_assigning);
@@ -647,6 +705,10 @@ String ShaderCompilerGLES2::_dump_node_code(SL::Node *p_node, int p_level, Gener
}
code += ";\n";
} else if (cf_node->flow_op == SL::FLOW_OP_DISCARD) {
+ if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) {
+ *p_actions.usage_flag_pointers["DISCARD"] = true;
+ used_flag_pointers.insert("DISCARD");
+ }
code += "discard;";
} else if (cf_node->flow_op == SL::FLOW_OP_CONTINUE) {
code += "continue;";
@@ -721,8 +783,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth";
- actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp";
- actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color";
actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture";
actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture";
@@ -736,7 +796,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_HEIGHT"] = "light_height";
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_COLOR"] = "light_color";
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_UV"] = "light_uv";
- //actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT_SHADOW_COLOR"]="light_shadow_color";
actions[VS::SHADER_CANVAS_ITEM].renames["LIGHT"] = "light";
actions[VS::SHADER_CANVAS_ITEM].renames["SHADOW_COLOR"] = "shadow_color";
@@ -754,10 +813,10 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
/** SPATIAL SHADER **/
actions[VS::SHADER_SPATIAL].renames["WORLD_MATRIX"] = "world_transform";
- 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["INV_CAMERA_MATRIX"] = "camera_matrix";
+ actions[VS::SHADER_SPATIAL].renames["CAMERA_MATRIX"] = "camera_inverse_matrix";
actions[VS::SHADER_SPATIAL].renames["PROJECTION_MATRIX"] = "projection_matrix";
- actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "inv_projection_matrix";
+ actions[VS::SHADER_SPATIAL].renames["INV_PROJECTION_MATRIX"] = "projection_inverse_matrix";
actions[VS::SHADER_SPATIAL].renames["MODELVIEW_MATRIX"] = "modelview";
actions[VS::SHADER_SPATIAL].renames["VERTEX"] = "vertex.xyz";
@@ -768,7 +827,8 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize";
- //actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"]=ShaderLanguage::TYPE_INT;
+ // gl_InstanceID is not available in OpenGL ES 2.0
+ actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "0";
//builtins
@@ -790,13 +850,11 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
- //actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"] = "sss_spread";
actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
actions[VS::SHADER_SPATIAL].renames["AO"] = "ao";
actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
- //actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2;
actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
@@ -838,8 +896,6 @@ ShaderCompilerGLES2::ShaderCompilerGLES2() {
actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
-
actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
diff --git a/drivers/gles2/shader_gles2.cpp b/drivers/gles2/shader_gles2.cpp
index fa9562877d..3b2a29d3ee 100644
--- a/drivers/gles2/shader_gles2.cpp
+++ b/drivers/gles2/shader_gles2.cpp
@@ -33,7 +33,10 @@
#include "print_string.h"
#include "string_builder.h"
-//#define DEBUG_OPENGL
+#include "rasterizer_gles2.h"
+#include "rasterizer_storage_gles2.h"
+
+// #define DEBUG_OPENGL
// #include "shaders/copy.glsl.gen.h"
@@ -54,7 +57,7 @@
ShaderGLES2 *ShaderGLES2::active = NULL;
-//#define DEBUG_SHADER
+// #define DEBUG_SHADER
#ifdef DEBUG_SHADER
@@ -83,7 +86,10 @@ void ShaderGLES2::bind_uniforms() {
continue;
}
- const Variant &v = E->value();
+ Variant v;
+
+ v = E->value();
+
_set_uniform_variant(location, v);
E = E->next();
}
@@ -128,6 +134,28 @@ bool ShaderGLES2::bind() {
glUseProgram(version->id);
+ // find out uniform names and locations
+
+ int count;
+ glGetProgramiv(version->id, GL_ACTIVE_UNIFORMS, &count);
+ version->uniform_names.resize(count);
+
+ for (int i = 0; i < count; i++) {
+ GLchar uniform_name[1024];
+ int len = 0;
+ GLint size = 0;
+ GLenum type;
+
+ glGetActiveUniform(version->id, i, 1024, &len, &size, &type, uniform_name);
+
+ uniform_name[len] = '\0';
+ String name = String((const char *)uniform_name);
+
+ version->uniform_names.write[i] = name;
+ }
+
+ bind_uniforms();
+
DEBUG_TEST_ERROR("use program");
active = this;
@@ -203,7 +231,6 @@ static String _fix_error_code_line(const String &p_error, int p_code_start, int
continue;
String numstr = error.substr(last_find_pos + 1, (end_pos - last_find_pos) - 1);
- print_line("numstr: " + numstr);
String begin = error.substr(0, last_find_pos + 1);
String end = error.substr(end_pos, error.length());
int num = numstr.to_int() + p_code_start - p_offset;
@@ -228,7 +255,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
}
if (!_v)
- version_map[conditional_version];
+ version_map[conditional_version] = Version();
Version &v = version_map[conditional_version];
@@ -288,7 +315,7 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
if (cc) {
for (int i = 0; i < cc->custom_defines.size(); i++) {
- strings.push_back(cc->custom_defines[i]);
+ strings.push_back(cc->custom_defines.write[i]);
DEBUG_PRINT("CD #" + itos(i) + ": " + String(cc->custom_defines[i]));
}
}
@@ -389,6 +416,10 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
strings.push_back(fragment_code3.get_data());
#ifdef DEBUG_SHADER
+
+ if (cc) {
+ DEBUG_PRINT("\nFragment Code:\n\n" + String(cc->fragment_globals));
+ }
DEBUG_PRINT("\nFragment Code:\n\n" + String(code_string.get_data()));
#endif
@@ -495,14 +526,28 @@ ShaderGLES2::Version *ShaderGLES2::get_current_version() {
for (int i = 0; i < texunit_pair_count; i++) {
GLint loc = glGetUniformLocation(v.id, texunit_pairs[i].name);
- if (loc >= 0)
- glUniform1i(loc, texunit_pairs[i].index);
+ if (loc >= 0) {
+ if (texunit_pairs[i].index < 0) {
+ glUniform1i(loc, max_image_units + texunit_pairs[i].index);
+ } else {
+ glUniform1i(loc, texunit_pairs[i].index);
+ }
+ }
}
if (cc) {
- v.custom_uniform_locations.resize(cc->custom_uniforms.size());
+ // uniforms
for (int i = 0; i < cc->custom_uniforms.size(); i++) {
- v.custom_uniform_locations[i] = glGetUniformLocation(v.id, String(cc->custom_uniforms[i]).ascii().get_data());
+ StringName native_uniform_name = "m_" + cc->custom_uniforms[i];
+ GLint location = glGetUniformLocation(v.id, ((String)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());
+ v.custom_uniform_locations[cc->texture_uniforms[i]] = location;
}
}
@@ -602,6 +647,8 @@ void ShaderGLES2::setup(
}
}
}
+
+ glGetIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &max_image_units);
}
void ShaderGLES2::finish() {
@@ -660,6 +707,7 @@ void ShaderGLES2::set_custom_shader_code(uint32_t p_code_id,
cc->light = p_light;
cc->custom_uniforms = p_uniforms;
cc->custom_defines = p_custom_defines;
+ cc->texture_uniforms = p_texture_uniforms;
cc->version++;
}
@@ -675,6 +723,367 @@ void ShaderGLES2::free_custom_shader(uint32_t p_code_id) {
custom_code_map.erase(p_code_id);
}
+void ShaderGLES2::use_material(void *p_material) {
+ RasterizerStorageGLES2::Material *material = (RasterizerStorageGLES2::Material *)p_material;
+
+ if (!material) {
+ return;
+ }
+
+ if (!material->shader) {
+ return;
+ }
+
+ Version *v = version_map.getptr(conditional_version);
+
+ CustomCode *cc = NULL;
+ if (v) {
+ cc = custom_code_map.getptr(v->code_version);
+ }
+
+ // bind uniforms
+ for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) {
+
+ if (E->get().texture_order >= 0)
+ continue; // this is a texture, doesn't go here
+
+ Map<StringName, Variant>::Element *V = material->params.find(E->key());
+
+ Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > value;
+
+ value.first = E->get().type;
+ value.second = E->get().default_value;
+
+ if (V) {
+ value.second = Vector<ShaderLanguage::ConstantNode::Value>();
+ value.second.resize(E->get().default_value.size());
+ switch (E->get().type) {
+ case ShaderLanguage::TYPE_BOOL: {
+ if (value.second.size() < 1)
+ value.second.resize(1);
+ value.second.write[0].boolean = V->get();
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC2: {
+ if (value.second.size() < 2)
+ value.second.resize(2);
+ int flags = V->get();
+ value.second.write[0].boolean = flags & 1;
+ value.second.write[1].boolean = flags & 2;
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC3: {
+ if (value.second.size() < 3)
+ value.second.resize(3);
+ int flags = V->get();
+ value.second.write[0].boolean = flags & 1;
+ value.second.write[1].boolean = flags & 2;
+ value.second.write[2].boolean = flags & 4;
+
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC4: {
+ if (value.second.size() < 4)
+ value.second.resize(4);
+ int flags = V->get();
+ value.second.write[0].boolean = flags & 1;
+ value.second.write[1].boolean = flags & 2;
+ value.second.write[2].boolean = flags & 4;
+ value.second.write[3].boolean = flags & 8;
+
+ } break;
+
+ case ShaderLanguage::TYPE_INT: {
+ if (value.second.size() < 1)
+ value.second.resize(1);
+ int val = V->get();
+ value.second.write[0].sint = val;
+ } break;
+
+ case ShaderLanguage::TYPE_IVEC2: {
+ if (value.second.size() < 2)
+ value.second.resize(2);
+ PoolIntArray val = V->get();
+ for (int i = 0; i < val.size(); i++) {
+ value.second.write[i].sint = val[i];
+ }
+ } break;
+
+ case ShaderLanguage::TYPE_IVEC3: {
+ if (value.second.size() < 3)
+ value.second.resize(3);
+ PoolIntArray val = V->get();
+ for (int i = 0; i < val.size(); i++) {
+ value.second.write[i].sint = val[i];
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_IVEC4: {
+ if (value.second.size() < 4)
+ value.second.resize(4);
+ PoolIntArray val = V->get();
+ for (int i = 0; i < val.size(); i++) {
+ value.second.write[i].sint = val[i];
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_UINT: {
+ if (value.second.size() < 1)
+ value.second.resize(1);
+ uint32_t val = V->get();
+ value.second.write[0].uint = val;
+ } break;
+
+ case ShaderLanguage::TYPE_UVEC2: {
+ if (value.second.size() < 2)
+ value.second.resize(2);
+ PoolIntArray val = V->get();
+ for (int i = 0; i < val.size(); i++) {
+ value.second.write[i].uint = val[i];
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_UVEC3: {
+ if (value.second.size() < 3)
+ value.second.resize(3);
+ PoolIntArray val = V->get();
+ for (int i = 0; i < val.size(); i++) {
+ value.second.write[i].uint = val[i];
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_UVEC4: {
+ if (value.second.size() < 4)
+ value.second.resize(4);
+ PoolIntArray val = V->get();
+ for (int i = 0; i < val.size(); i++) {
+ value.second.write[i].uint = val[i];
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_FLOAT: {
+ if (value.second.size() < 1)
+ value.second.resize(1);
+ value.second.write[0].real = V->get();
+
+ } break;
+
+ case ShaderLanguage::TYPE_VEC2: {
+ if (value.second.size() < 2)
+ value.second.resize(2);
+ Vector2 val = V->get();
+ value.second.write[0].real = val.x;
+ value.second.write[1].real = val.y;
+ } break;
+
+ case ShaderLanguage::TYPE_VEC3: {
+ if (value.second.size() < 3)
+ value.second.resize(3);
+ Vector3 val = V->get();
+ value.second.write[0].real = val.x;
+ value.second.write[1].real = val.y;
+ value.second.write[2].real = val.z;
+ } break;
+
+ case ShaderLanguage::TYPE_VEC4: {
+ if (value.second.size() < 4)
+ value.second.resize(4);
+ if (V->get().get_type() == Variant::PLANE) {
+ Plane val = V->get();
+ value.second.write[0].real = val.normal.x;
+ value.second.write[1].real = val.normal.y;
+ value.second.write[2].real = val.normal.z;
+ value.second.write[3].real = val.d;
+ } else {
+ Color val = V->get();
+ value.second.write[0].real = val.r;
+ value.second.write[1].real = val.g;
+ value.second.write[2].real = val.b;
+ value.second.write[3].real = val.a;
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_MAT2: {
+ Transform2D val = V->get();
+
+ if (value.second.size() < 4) {
+ value.second.resize(4);
+ }
+
+ value.second.write[0].real = val.elements[0][0];
+ value.second.write[1].real = val.elements[0][1];
+ value.second.write[2].real = val.elements[1][0];
+ value.second.write[3].real = val.elements[1][1];
+
+ } break;
+
+ case ShaderLanguage::TYPE_MAT3: {
+ Basis val = V->get();
+
+ if (value.second.size() < 9) {
+ value.second.resize(9);
+ }
+
+ value.second.write[0].real = val.elements[0][0];
+ value.second.write[1].real = val.elements[0][1];
+ value.second.write[2].real = val.elements[0][2];
+ value.second.write[3].real = val.elements[1][0];
+ value.second.write[4].real = val.elements[1][1];
+ value.second.write[5].real = val.elements[1][2];
+ value.second.write[6].real = val.elements[2][0];
+ value.second.write[7].real = val.elements[2][1];
+ value.second.write[8].real = val.elements[2][2];
+ } break;
+
+ case ShaderLanguage::TYPE_MAT4: {
+ Transform val = V->get();
+
+ if (value.second.size() < 16) {
+ value.second.resize(16);
+ }
+
+ value.second.write[0].real = val.basis.elements[0][0];
+ value.second.write[1].real = val.basis.elements[0][1];
+ value.second.write[2].real = val.basis.elements[0][2];
+ value.second.write[3].real = 0;
+ value.second.write[4].real = val.basis.elements[1][0];
+ value.second.write[5].real = val.basis.elements[1][1];
+ value.second.write[6].real = val.basis.elements[1][2];
+ value.second.write[7].real = 0;
+ value.second.write[8].real = val.basis.elements[2][0];
+ value.second.write[9].real = val.basis.elements[2][1];
+ value.second.write[10].real = val.basis.elements[2][2];
+ value.second.write[11].real = 0;
+ value.second.write[12].real = val.origin[0];
+ value.second.write[13].real = val.origin[1];
+ value.second.write[14].real = val.origin[2];
+ value.second.write[15].real = 1;
+ } break;
+
+ default: {
+
+ } break;
+ }
+ } else {
+ if (value.second.size() == 0) {
+ // No default value set... weird, let's just use zero for everything
+ size_t default_arg_size = 1;
+ bool is_float = false;
+ switch (E->get().type) {
+ case ShaderLanguage::TYPE_BOOL:
+ case ShaderLanguage::TYPE_INT:
+ case ShaderLanguage::TYPE_UINT: {
+ default_arg_size = 1;
+ } break;
+
+ case ShaderLanguage::TYPE_FLOAT: {
+ default_arg_size = 1;
+ is_float = true;
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC2:
+ case ShaderLanguage::TYPE_IVEC2:
+ case ShaderLanguage::TYPE_UVEC2: {
+ default_arg_size = 2;
+ } break;
+
+ case ShaderLanguage::TYPE_VEC2: {
+ default_arg_size = 2;
+ is_float = true;
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC3:
+ case ShaderLanguage::TYPE_IVEC3:
+ case ShaderLanguage::TYPE_UVEC3: {
+ default_arg_size = 3;
+ } break;
+
+ case ShaderLanguage::TYPE_VEC3: {
+ default_arg_size = 3;
+ is_float = true;
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC4:
+ case ShaderLanguage::TYPE_IVEC4:
+ case ShaderLanguage::TYPE_UVEC4: {
+ default_arg_size = 4;
+ } break;
+
+ case ShaderLanguage::TYPE_VEC4: {
+ default_arg_size = 4;
+ is_float = true;
+ } break;
+
+ default: {
+ // TODO matricies and all that stuff
+ default_arg_size = 1;
+ } break;
+ }
+
+ value.second.resize(default_arg_size);
+
+ for (int i = 0; i < default_arg_size; i++) {
+ if (is_float) {
+ value.second.write[i].real = 0.0;
+ } else {
+ value.second.write[i].uint = 0;
+ }
+ }
+ }
+ }
+
+ // GLint location = get_uniform_location(E->key());
+
+ GLint location;
+ if (v->custom_uniform_locations.has(E->key())) {
+ location = v->custom_uniform_locations[E->key()];
+ } else {
+ int idx = v->uniform_names.find(E->key()); // TODO maybe put those in a Map?
+ if (idx < 0) {
+ location = -1;
+ } else {
+ location = v->uniform_location[idx];
+ }
+ }
+
+ _set_uniform_value(location, value);
+ }
+
+ // bind textures
+ 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;
+ value.first = ShaderLanguage::TYPE_INT;
+ value.second.resize(1);
+ value.second.write[0].sint = i;
+
+ // GLint location = get_uniform_location(textures[i].first);
+
+ // if (location < 0) {
+ // location = material->shader->uniform_locations[textures[i].first];
+ // }
+ GLint location = -1;
+ if (v->custom_uniform_locations.has(textures[i].first)) {
+ location = v->custom_uniform_locations[textures[i].first];
+ } else {
+ location = get_uniform_location(textures[i].first);
+ }
+
+ _set_uniform_value(location, value);
+ }
+}
+
void ShaderGLES2::set_base_material_tex_index(int p_idx) {
}
diff --git a/drivers/gles2/shader_gles2.h b/drivers/gles2/shader_gles2.h
index c3635bc201..cb515c199c 100644
--- a/drivers/gles2/shader_gles2.h
+++ b/drivers/gles2/shader_gles2.h
@@ -44,6 +44,11 @@
#include "map.h"
#include "variant.h"
+#include "core/pair.h"
+#include "servers/visual/shader_language.h"
+
+class RasterizerStorageGLES2;
+
class ShaderGLES2 {
protected:
struct Enum {
@@ -105,9 +110,10 @@ private:
GLuint id;
GLuint vert_id;
GLuint frag_id;
+ Vector<StringName> uniform_names;
GLint *uniform_location;
Vector<GLint> texture_uniform_locations;
- Vector<GLint> custom_uniform_locations;
+ Map<StringName, GLint> custom_uniform_locations;
uint32_t code_version;
bool ok;
Version() {
@@ -169,6 +175,168 @@ private:
int max_image_units;
+ Map<uint32_t, Variant> uniform_defaults;
+ Map<uint32_t, CameraMatrix> uniform_cameras;
+
+ Map<StringName, Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > > uniform_values;
+
+protected:
+ _FORCE_INLINE_ int _get_uniform(int p_which) const;
+ _FORCE_INLINE_ void _set_conditional(int p_which, bool p_value);
+
+ void setup(const char **p_conditional_defines,
+ int p_conditional_count,
+ const char **p_uniform_names,
+ int p_uniform_count,
+ const AttributePair *p_attribute_pairs,
+ int p_attribute_count,
+ const TexUnitPair *p_texunit_pairs,
+ int p_texunit_pair_count,
+ const char *p_vertex_code,
+ const char *p_fragment_code,
+ int p_vertex_code_start,
+ int p_fragment_code_start);
+
+ ShaderGLES2();
+
+public:
+ enum {
+ CUSTOM_SHADER_DISABLED = 0
+ };
+
+ GLint get_uniform_location(const String &p_name) const;
+ GLint get_uniform_location(int p_index) const;
+
+ static _FORCE_INLINE_ ShaderGLES2 *get_active() { return active; }
+ bool bind();
+ void unbind();
+ void bind_uniforms();
+
+ inline GLuint get_program() const { return version ? version->id : 0; }
+
+ void clear_caches();
+
+ _FORCE_INLINE_ void _set_uniform_value(GLint p_uniform, const Pair<ShaderLanguage::DataType, Vector<ShaderLanguage::ConstantNode::Value> > &value) {
+ if (p_uniform < 0)
+ return;
+
+ const Vector<ShaderLanguage::ConstantNode::Value> &values = value.second;
+
+ switch (value.first) {
+ case ShaderLanguage::TYPE_BOOL: {
+ glUniform1i(p_uniform, values[0].boolean);
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC2: {
+ glUniform2i(p_uniform, values[0].boolean, values[1].boolean);
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC3: {
+ glUniform3i(p_uniform, values[0].boolean, values[1].boolean, values[2].boolean);
+ } break;
+
+ case ShaderLanguage::TYPE_BVEC4: {
+ glUniform4i(p_uniform, values[0].boolean, values[1].boolean, values[2].boolean, values[3].boolean);
+ } break;
+
+ case ShaderLanguage::TYPE_INT: {
+ glUniform1i(p_uniform, values[0].sint);
+ } break;
+
+ case ShaderLanguage::TYPE_IVEC2: {
+ glUniform2i(p_uniform, values[0].sint, values[1].sint);
+ } break;
+
+ case ShaderLanguage::TYPE_IVEC3: {
+ glUniform3i(p_uniform, values[0].sint, values[1].sint, values[2].sint);
+ } break;
+
+ case ShaderLanguage::TYPE_IVEC4: {
+ glUniform4i(p_uniform, values[0].sint, values[1].sint, values[2].sint, values[3].sint);
+ } break;
+
+ case ShaderLanguage::TYPE_UINT: {
+ glUniform1i(p_uniform, values[0].uint);
+ } break;
+
+ case ShaderLanguage::TYPE_UVEC2: {
+ glUniform2i(p_uniform, values[0].uint, values[1].uint);
+ } break;
+
+ case ShaderLanguage::TYPE_UVEC3: {
+ glUniform3i(p_uniform, values[0].uint, values[1].uint, values[2].uint);
+ } break;
+
+ case ShaderLanguage::TYPE_UVEC4: {
+ glUniform4i(p_uniform, values[0].uint, values[1].uint, values[2].uint, values[3].uint);
+ } break;
+
+ case ShaderLanguage::TYPE_FLOAT: {
+ glUniform1f(p_uniform, values[0].real);
+ } break;
+
+ case ShaderLanguage::TYPE_VEC2: {
+ glUniform2f(p_uniform, values[0].real, values[1].real);
+ } break;
+
+ case ShaderLanguage::TYPE_VEC3: {
+ glUniform3f(p_uniform, values[0].real, values[1].real, values[2].real);
+ } break;
+
+ case ShaderLanguage::TYPE_VEC4: {
+ glUniform4f(p_uniform, values[0].real, values[1].real, values[2].real, values[3].real);
+ } break;
+
+ case ShaderLanguage::TYPE_MAT2: {
+ GLfloat mat[4];
+
+ for (int i = 0; i < 4; i++) {
+ mat[i] = values[i].real;
+ }
+
+ glUniformMatrix2fv(p_uniform, 1, GL_FALSE, mat);
+ } break;
+
+ case ShaderLanguage::TYPE_MAT3: {
+ GLfloat mat[9];
+
+ for (int i = 0; i < 9; i++) {
+ mat[i] = values[i].real;
+ }
+
+ glUniformMatrix3fv(p_uniform, 1, GL_FALSE, mat);
+
+ } break;
+
+ case ShaderLanguage::TYPE_MAT4: {
+ GLfloat mat[16];
+
+ for (int i = 0; i < 16; i++) {
+ mat[i] = values[i].real;
+ }
+
+ glUniformMatrix4fv(p_uniform, 1, GL_FALSE, mat);
+
+ } break;
+
+ case ShaderLanguage::TYPE_SAMPLER2D: {
+
+ } break;
+
+ case ShaderLanguage::TYPE_ISAMPLER2D: {
+
+ } break;
+
+ case ShaderLanguage::TYPE_USAMPLER2D: {
+
+ } break;
+
+ case ShaderLanguage::TYPE_SAMPLERCUBE: {
+
+ } break;
+ }
+ }
+
_FORCE_INLINE_ void _set_uniform_variant(GLint p_uniform, const Variant &p_value) {
if (p_uniform < 0)
@@ -262,49 +430,13 @@ private:
glUniformMatrix4fv(p_uniform, 1, false, matrix);
} break;
+ case Variant::OBJECT: {
+
+ } break;
default: { ERR_FAIL(); } // do nothing
}
}
- Map<uint32_t, Variant> uniform_defaults;
- Map<uint32_t, CameraMatrix> uniform_cameras;
-
-protected:
- _FORCE_INLINE_ int _get_uniform(int p_which) const;
- _FORCE_INLINE_ void _set_conditional(int p_which, bool p_value);
-
- void setup(const char **p_conditional_defines,
- int p_conditional_count,
- const char **p_uniform_names,
- int p_uniform_count,
- const AttributePair *p_attribute_pairs,
- int p_attribute_count,
- const TexUnitPair *p_texunit_pairs,
- int p_texunit_pair_count,
- const char *p_vertex_code,
- const char *p_fragment_code,
- int p_vertex_code_start,
- int p_fragment_code_start);
-
- ShaderGLES2();
-
-public:
- enum {
- CUSTOM_SHADER_DISABLED = 0
- };
-
- GLint get_uniform_location(const String &p_name) const;
- GLint get_uniform_location(int p_index) const;
-
- static _FORCE_INLINE_ ShaderGLES2 *get_active() { return active; }
- bool bind();
- void unbind();
- void bind_uniforms();
-
- inline GLuint get_program() const { return version ? version->id : 0; }
-
- void clear_caches();
-
uint32_t create_custom_shader();
void set_custom_shader_code(uint32_t p_code_id,
const String &p_vertex,
@@ -331,6 +463,10 @@ public:
uniforms_dirty = true;
}
+ // this void* is actually a RasterizerStorageGLES2::Material, but C++ doesn't
+ // like forward declared nested classes.
+ void use_material(void *p_material);
+
uint32_t get_version() const { return new_conditional_version.version; }
void set_uniform_camera(int p_idx, const CameraMatrix &p_mat) {
diff --git a/drivers/gles2/shaders/SCsub b/drivers/gles2/shaders/SCsub
index 5de3e1ac90..acb93fff8f 100644
--- a/drivers/gles2/shaders/SCsub
+++ b/drivers/gles2/shaders/SCsub
@@ -8,8 +8,8 @@ if 'GLES2_GLSL' in env['BUILDERS']:
env.GLES2_GLSL('canvas.glsl');
# env.GLES2_GLSL('canvas_shadow.glsl');
env.GLES2_GLSL('scene.glsl');
-# env.GLES2_GLSL('cubemap_filter.glsl');
-# env.GLES2_GLSL('cube_to_dp.glsl');
+ env.GLES2_GLSL('cubemap_filter.glsl');
+ env.GLES2_GLSL('cube_to_dp.glsl');
# env.GLES2_GLSL('blend_shape.glsl');
# env.GLES2_GLSL('screen_space_reflection.glsl');
# env.GLES2_GLSL('effect_blur.glsl');
diff --git a/drivers/gles2/shaders/blend_shape.glsl b/drivers/gles2/shaders/blend_shape.glsl
index 4e0d066823..a1e954e33d 100644
--- a/drivers/gles2/shaders/blend_shape.glsl
+++ b/drivers/gles2/shaders/blend_shape.glsl
@@ -1,6 +1,6 @@
+/* clang-format off */
[vertex]
-
/*
from VisualServer:
@@ -23,56 +23,57 @@ ARRAY_INDEX=8,
/* INPUT ATTRIBS */
-layout(location=0) in highp VFORMAT vertex_attrib;
-layout(location=1) in vec3 normal_attrib;
+layout(location = 0) in highp VFORMAT vertex_attrib;
+/* clang-format on */
+layout(location = 1) in vec3 normal_attrib;
#ifdef ENABLE_TANGENT
-layout(location=2) in vec4 tangent_attrib;
+layout(location = 2) in vec4 tangent_attrib;
#endif
#ifdef ENABLE_COLOR
-layout(location=3) in vec4 color_attrib;
+layout(location = 3) in vec4 color_attrib;
#endif
#ifdef ENABLE_UV
-layout(location=4) in vec2 uv_attrib;
+layout(location = 4) in vec2 uv_attrib;
#endif
#ifdef ENABLE_UV2
-layout(location=5) in vec2 uv2_attrib;
+layout(location = 5) in vec2 uv2_attrib;
#endif
#ifdef ENABLE_SKELETON
-layout(location=6) in ivec4 bone_attrib;
-layout(location=7) in vec4 weight_attrib;
+layout(location = 6) in ivec4 bone_attrib;
+layout(location = 7) in vec4 weight_attrib;
#endif
/* BLEND ATTRIBS */
#ifdef ENABLE_BLEND
-layout(location=8) in highp VFORMAT vertex_attrib_blend;
-layout(location=9) in vec3 normal_attrib_blend;
+layout(location = 8) in highp VFORMAT vertex_attrib_blend;
+layout(location = 9) in vec3 normal_attrib_blend;
#ifdef ENABLE_TANGENT
-layout(location=10) in vec4 tangent_attrib_blend;
+layout(location = 10) in vec4 tangent_attrib_blend;
#endif
#ifdef ENABLE_COLOR
-layout(location=11) in vec4 color_attrib_blend;
+layout(location = 11) in vec4 color_attrib_blend;
#endif
#ifdef ENABLE_UV
-layout(location=12) in vec2 uv_attrib_blend;
+layout(location = 12) in vec2 uv_attrib_blend;
#endif
#ifdef ENABLE_UV2
-layout(location=13) in vec2 uv2_attrib_blend;
+layout(location = 13) in vec2 uv2_attrib_blend;
#endif
#ifdef ENABLE_SKELETON
-layout(location=14) in ivec4 bone_attrib_blend;
-layout(location=15) in vec4 weight_attrib_blend;
+layout(location = 14) in ivec4 bone_attrib_blend;
+layout(location = 15) in vec4 weight_attrib_blend;
#endif
#endif
@@ -110,7 +111,6 @@ uniform float blend_amount;
void main() {
-
#ifdef ENABLE_BLEND
vertex_out = vertex_attrib_blend + vertex_attrib * blend_amount;
@@ -140,7 +140,6 @@ void main() {
uv2_out = uv2_attrib_blend + uv2_attrib * blend_amount;
#endif
-
#ifdef ENABLE_SKELETON
bone_out = bone_attrib_blend;
@@ -149,7 +148,6 @@ void main() {
#else //ENABLE_BLEND
-
vertex_out = vertex_attrib * blend_amount;
#ifdef ENABLE_NORMAL
@@ -177,7 +175,6 @@ void main() {
uv2_out = uv2_attrib * blend_amount;
#endif
-
#ifdef ENABLE_SKELETON
bone_out = bone_attrib;
@@ -188,10 +185,10 @@ void main() {
gl_Position = vec4(0.0);
}
+/* clang-format off */
[fragment]
-
void main() {
}
-
+/* clang-format on */
diff --git a/drivers/gles2/shaders/canvas.glsl b/drivers/gles2/shaders/canvas.glsl
index 11c6ab9b76..ba69ca9b6e 100644
--- a/drivers/gles2/shaders/canvas.glsl
+++ b/drivers/gles2/shaders/canvas.glsl
@@ -1,3 +1,4 @@
+/* clang-format off */
[vertex]
#ifdef USE_GLES_OVER_GL
@@ -9,6 +10,7 @@ precision mediump int;
#endif
uniform highp mat4 projection_matrix;
+/* clang-format on */
uniform highp mat4 modelview_matrix;
uniform highp mat4 extra_matrix;
attribute highp vec2 vertex; // attrib:0
@@ -27,10 +29,14 @@ uniform vec4 src_rect;
#endif
-uniform bool blit_pass;
+uniform highp float time;
+
+/* clang-format off */
VERTEX_SHADER_GLOBALS
+/* clang-format on */
+
vec2 select(vec2 a, vec2 b, bvec2 c) {
vec2 ret;
@@ -74,18 +80,21 @@ void main() {
#endif
-{
- vec2 src_vtx=outvec.xy;
+ {
+ vec2 src_vtx = outvec.xy;
+ /* clang-format off */
+
VERTEX_SHADER_CODE
-}
+ /* clang-format on */
+ }
color_interp = color;
gl_Position = projection_matrix * modelview_matrix * outvec;
-
}
+/* clang-format off */
[fragment]
#ifdef USE_GLES_OVER_GL
@@ -96,20 +105,21 @@ precision mediump float;
precision mediump int;
#endif
-uniform sampler2D color_texture; // texunit:0
+uniform sampler2D color_texture; // texunit:-1
+/* clang-format on */
uniform highp vec2 color_texpixel_size;
-uniform mediump sampler2D normal_texture; // texunit:1
+uniform mediump sampler2D normal_texture; // texunit:-2
varying mediump vec2 uv_interp;
varying mediump vec4 color_interp;
-uniform bool blit_pass;
+uniform highp float time;
uniform vec4 final_modulate;
#ifdef SCREEN_TEXTURE_USED
-uniform sampler2D screen_texture; // texunit:2
+uniform sampler2D screen_texture; // texunit:-3
#endif
@@ -119,23 +129,30 @@ uniform vec2 screen_pixel_size;
#endif
+/* clang-format off */
+
FRAGMENT_SHADER_GLOBALS
+/* clang-format on */
void main() {
vec4 color = color_interp;
color *= texture2D(color_texture, uv_interp);
-{
-FRAGMENT_SHADER_CODE
+#ifdef SCREEN_UV_USED
+ vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
+#endif
+ {
+ /* clang-format off */
+FRAGMENT_SHADER_CODE
-}
+ /* clang-format on */
+ }
color *= final_modulate;
gl_FragColor = color;
-
}
diff --git a/drivers/gles2/shaders/canvas_shadow.glsl b/drivers/gles2/shaders/canvas_shadow.glsl
index c757990de0..e3c8140e31 100644
--- a/drivers/gles2/shaders/canvas_shadow.glsl
+++ b/drivers/gles2/shaders/canvas_shadow.glsl
@@ -1,49 +1,50 @@
+/* clang-format off */
[vertex]
-
-
uniform highp mat4 projection_matrix;
+/* clang-format on */
uniform highp mat4 light_matrix;
uniform highp mat4 world_matrix;
uniform highp float distance_norm;
-layout(location=0) in highp vec3 vertex;
+layout(location = 0) in highp vec3 vertex;
out highp vec4 position_interp;
void main() {
- gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0)));
- position_interp=gl_Position;
+ gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex, 1.0)));
+ position_interp = gl_Position;
}
+/* clang-format off */
[fragment]
in highp vec4 position_interp;
+/* clang-format on */
#ifdef USE_RGBA_SHADOWS
-layout(location=0) out lowp vec4 distance_buf;
+layout(location = 0) out lowp vec4 distance_buf;
#else
-layout(location=0) out highp float distance_buf;
+layout(location = 0) out highp float distance_buf;
#endif
void main() {
- highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias;
+ highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; //bias;
#ifdef USE_RGBA_SHADOWS
highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
- distance_buf=comp;
+ distance_buf = comp;
#else
- distance_buf=depth;
+ distance_buf = depth;
#endif
}
-
diff --git a/drivers/gles2/shaders/copy.glsl b/drivers/gles2/shaders/copy.glsl
index a21da68525..16bbde196d 100644
--- a/drivers/gles2/shaders/copy.glsl
+++ b/drivers/gles2/shaders/copy.glsl
@@ -1,3 +1,4 @@
+/* clang-format off */
[vertex]
#ifdef USE_GLES_OVER_GL
@@ -9,11 +10,21 @@ precision mediump int;
#endif
attribute highp vec4 vertex_attrib; // attrib:0
+/* clang-format on */
+
+#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
+attribute vec3 cube_in; // attrib:4
+#else
attribute vec2 uv_in; // attrib:4
+#endif
+
attribute vec2 uv2_in; // attrib:5
+#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
+varying vec3 cube_interp;
+#else
varying vec2 uv_interp;
-
+#endif
varying vec2 uv2_interp;
#ifdef USE_COPY_SECTION
@@ -22,7 +33,12 @@ uniform vec4 copy_section;
void main() {
+#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
+ cube_interp = cube_in;
+#else
uv_interp = uv_in;
+#endif
+
uv2_interp = uv2_in;
gl_Position = vertex_attrib;
@@ -32,8 +48,11 @@ void main() {
#endif
}
+/* clang-format off */
[fragment]
+#define M_PI 3.14159265359
+
#ifdef USE_GLES_OVER_GL
#define mediump
#define highp
@@ -42,31 +61,70 @@ precision mediump float;
precision mediump int;
#endif
-
+#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
+varying vec3 cube_interp;
+#else
varying vec2 uv_interp;
+#endif
+/* clang-format on */
+
+#ifdef USE_CUBEMAP
+uniform samplerCube source_cube; // texunit:0
+#else
uniform sampler2D source; // texunit:0
+#endif
varying vec2 uv2_interp;
+#ifdef USE_MULTIPLIER
+uniform float multiplier;
+#endif
+
#ifdef USE_CUSTOM_ALPHA
uniform float custom_alpha;
#endif
+#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO)
+
+vec4 texturePanorama(sampler2D pano, vec3 normal) {
+
+ vec2 st = vec2(
+ atan(normal.x, normal.z),
+ acos(normal.y));
+
+ if (st.x < 0.0)
+ st.x += M_PI * 2.0;
+
+ st /= vec2(M_PI * 2.0, M_PI);
+
+ return texture2D(pano, st);
+}
+
+#endif
void main() {
- //vec4 color = color_interp;
- vec4 color = texture2D( source, uv_interp );
+#ifdef USE_PANORAMA
+ vec4 color = texturePanorama(source, normalize(cube_interp));
+
+#elif defined(USE_CUBEMAP)
+ vec4 color = textureCube(source_cube, normalize(cube_interp));
+#else
+ vec4 color = texture2D(source, uv_interp);
+#endif
#ifdef USE_NO_ALPHA
- color.a=1.0;
+ color.a = 1.0;
#endif
#ifdef USE_CUSTOM_ALPHA
- color.a=custom_alpha;
+ color.a = custom_alpha;
#endif
+#ifdef USE_MULTIPLIER
+ color.rgb *= multiplier;
+#endif
gl_FragColor = color;
}
diff --git a/drivers/gles2/shaders/cube_to_dp.glsl b/drivers/gles2/shaders/cube_to_dp.glsl
index 5ffc78c0b9..3d24c36336 100644
--- a/drivers/gles2/shaders/cube_to_dp.glsl
+++ b/drivers/gles2/shaders/cube_to_dp.glsl
@@ -1,10 +1,19 @@
+/* clang-format off */
[vertex]
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
+#endif
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+attribute highp vec4 vertex_attrib; // attrib:0
+/* clang-format on */
+attribute vec2 uv_in; // attrib:4
-out vec2 uv_interp;
+varying vec2 uv_interp;
void main() {
@@ -12,11 +21,20 @@ void main() {
gl_Position = vertex_attrib;
}
+/* clang-format off */
[fragment]
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
+#endif
uniform highp samplerCube source_cube; //texunit:0
-in vec2 uv_interp;
+/* clang-format on */
+varying vec2 uv_interp;
uniform bool z_flip;
uniform highp float z_far;
@@ -25,55 +43,53 @@ uniform highp float bias;
void main() {
- highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 );
-/*
- if(z_flip) {
- normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ highp vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0);
+ /*
+ if (z_flip) {
+ normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
} else {
- normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ normal.z = -0.5 + 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
}
-*/
+ */
- //normal.z = sqrt(1.0-dot(normal.xy,normal.xy));
- //normal.xy*=1.0+normal.z;
+ //normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
+ //normal.xy *= 1.0 + normal.z;
- normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
normal = normalize(normal);
+ /*
+ normal.z = 0.5;
+ normal = normalize(normal);
+ */
-/*
- normal.z=0.5;
- normal=normalize(normal);
-*/
if (!z_flip) {
- normal.z=-normal.z;
+ normal.z = -normal.z;
}
//normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 ));
- float depth = texture(source_cube,normal).r;
+ float depth = textureCube(source_cube, normal).r;
// absolute values for direction cosines, bigger value equals closer to basis axis
vec3 unorm = abs(normal);
- if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) {
- // x code
- unorm = normal.x > 0.0 ? vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ;
- } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) {
- // y code
- unorm = normal.y > 0.0 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 0.0, -1.0, 0.0 ) ;
- } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) {
- // z code
- unorm = normal.z > 0.0 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 0.0, 0.0, -1.0 ) ;
+ if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
+ // x code
+ unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0);
+ } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
+ // y code
+ unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0);
+ } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
+ // z code
+ unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
} else {
- // oh-no we messed up code
- // has to be
- unorm = vec3( 1.0, 0.0, 0.0 );
+ // oh-no we messed up code
+ // has to be
+ unorm = vec3(1.0, 0.0, 0.0);
}
- float depth_fix = 1.0 / dot(normal,unorm);
-
+ float depth_fix = 1.0 / dot(normal, unorm);
depth = 2.0 * depth - 1.0;
float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near));
- gl_FragDepth = (linear_depth*depth_fix+bias) / z_far;
+ gl_FragDepth = (linear_depth * depth_fix + bias) / z_far;
}
-
diff --git a/drivers/gles2/shaders/cubemap_filter.glsl b/drivers/gles2/shaders/cubemap_filter.glsl
index 485fbb6ee0..2a1ad8d8f2 100644
--- a/drivers/gles2/shaders/cubemap_filter.glsl
+++ b/drivers/gles2/shaders/cubemap_filter.glsl
@@ -1,125 +1,131 @@
+/* clang-format off */
[vertex]
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
+#endif
-layout(location=0) in highp vec2 vertex;
-
-layout(location=4) in highp vec2 uv;
+attribute highp vec2 vertex; // attrib:0
+/* clang-format on */
+attribute highp vec2 uv; // attrib:4
-out highp vec2 uv_interp;
+varying highp vec2 uv_interp;
void main() {
- uv_interp=uv;
- gl_Position=vec4(vertex,0,1);
+ uv_interp = uv;
+ gl_Position = vec4(vertex, 0, 1);
}
+/* clang-format off */
[fragment]
+#extension GL_ARB_shader_texture_lod : enable
-precision highp float;
-precision highp int;
-
-#ifdef USE_SOURCE_PANORAMA
-uniform sampler2D source_panorama; //texunit:0
+#ifndef GL_ARB_shader_texture_lod
+#define texture2DLod(img, coord, lod) texture2D(img, coord)
+#define textureCubeLod(img, coord, lod) textureCube(img, coord)
#endif
-#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
-uniform sampler2DArray source_dual_paraboloid_array; //texunit:0
-uniform int source_array_index;
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
#endif
-#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
+#ifdef USE_SOURCE_PANORAMA
+uniform sampler2D source_panorama; //texunit:0
+#else
uniform samplerCube source_cube; //texunit:0
#endif
+/* clang-format on */
uniform int face_id;
uniform float roughness;
-in highp vec2 uv_interp;
+varying highp vec2 uv_interp;
+
+uniform sampler2D radical_inverse_vdc_cache; // texunit:1
+
+#define M_PI 3.14159265359
+
+#ifdef LOW_QUALITY
+#define SAMPLE_COUNT 64
-layout(location = 0) out vec4 frag_color;
+#else
+#define SAMPLE_COUNT 512
-#define M_PI 3.14159265359
+#endif
+
+#ifdef USE_SOURCE_PANORAMA
+
+vec4 texturePanorama(sampler2D pano, vec3 normal) {
+
+ vec2 st = vec2(
+ atan(normal.x, normal.z),
+ acos(normal.y));
+
+ if (st.x < 0.0)
+ st.x += M_PI * 2.0;
+ st /= vec2(M_PI * 2.0, M_PI);
-vec3 texelCoordToVec(vec2 uv, int faceID)
-{
- mat3 faceUvVectors[6];
-/*
- // -x
- faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
- // +x
- faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
-
- // -y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
-
- // +y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
-
- // -z
- faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
-
- // +z
- faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
-*/
-
- // -x
- faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
- // +x
- faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face
-
- // -y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face
-
- // +y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face
-
- // -z
- faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face
-
- // +z
- faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face
-
- // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
- vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
- return normalize(result);
+ return texture2DLod(pano, st, 0.0);
}
-vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
-{
+#endif
+
+vec3 texelCoordToVec(vec2 uv, int faceID) {
+ mat3 faceUvVectors[6];
+
+ // -x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face
+
+ // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
+ return normalize(result);
+}
+
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
// Compute distribution direction
float Phi = 2.0 * M_PI * Xi.x;
- float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
+ float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
// Convert to spherical direction
@@ -136,159 +142,49 @@ vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
return TangentX * H.x + TangentY * H.y + N * H.z;
}
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float GGX(float NdotV, float a)
-{
- float k = a / 2.0;
- return NdotV / (NdotV * (1.0 - k) + k);
-}
-
-// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float G_Smith(float a, float nDotV, float nDotL)
-{
- return GGX(nDotL, a * a) * GGX(nDotV, a * a);
+float radical_inverse_VdC(int i) {
+ return texture2D(radical_inverse_vdc_cache, vec2(float(i) / 512.0, 0.0)).x;
}
-float radicalInverse_VdC(uint bits) {
- bits = (bits << 16u) | (bits >> 16u);
- bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
- bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
- bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
- bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
- return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+vec2 Hammersley(int i, int N) {
+ return vec2(float(i) / float(N), radical_inverse_VdC(i));
}
-vec2 Hammersley(uint i, uint N) {
- return vec2(float(i)/float(N), radicalInverse_VdC(i));
-}
-
-
-
-#ifdef LOW_QUALITY
-
-#define SAMPLE_COUNT 64u
-
-#else
-
-#define SAMPLE_COUNT 512u
-
-#endif
-
uniform bool z_flip;
-#ifdef USE_SOURCE_PANORAMA
-
-vec4 texturePanorama(vec3 normal,sampler2D pano ) {
-
- vec2 st = vec2(
- atan(normal.x, normal.z),
- acos(normal.y)
- );
-
- if(st.x < 0.0)
- st.x += M_PI*2.0;
-
- st/=vec2(M_PI*2.0,M_PI);
-
- return textureLod(pano,st,0.0);
-
-}
-
-#endif
-
-#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
-
-
-vec4 textureDualParaboloidArray(vec3 normal) {
-
- vec3 norm = normalize(normal);
- norm.xy/=1.0+abs(norm.z);
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
- if (norm.z<0.0) {
- norm.y=0.5-norm.y+0.5;
- }
- return textureLod(source_dual_paraboloid_array, vec3(norm.xy, float(source_array_index) ), 0.0);
-
-}
-
-#endif
-
void main() {
-#ifdef USE_DUAL_PARABOLOID
-
- vec3 N = vec3( uv_interp * 2.0 - 1.0, 0.0 );
- N.z = 0.5 - 0.5*((N.x * N.x) + (N.y * N.y));
- N = normalize(N);
-
- if (z_flip) {
- N.y=-N.y; //y is flipped to improve blending between both sides
- N.z=-N.z;
- }
-
-
-#else
- vec2 uv = (uv_interp * 2.0) - 1.0;
- vec3 N = texelCoordToVec(uv, face_id);
-#endif
- //vec4 color = color_interp;
-
-#ifdef USE_DIRECT_WRITE
-
-#ifdef USE_SOURCE_PANORAMA
-
- frag_color=vec4(texturePanorama(N,source_panorama).rgb,1.0);
-#endif
-
-#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
-
- frag_color=vec4(textureDualParaboloidArray(N).rgb,1.0);
-#endif
-
-#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
-
- N.y=-N.y;
- frag_color=vec4(texture(N,source_cube).rgb,1.0);
-#endif
+ vec3 color = vec3(0.0);
+ vec2 uv = (uv_interp * 2.0) - 1.0;
+ vec3 N = texelCoordToVec(uv, face_id);
+ vec4 sum = vec4(0.0);
+ for (int sample_num = 0; sample_num < SAMPLE_COUNT; sample_num++) {
-#else
+ vec2 xi = Hammersley(sample_num, SAMPLE_COUNT);
- vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
+ vec3 H = ImportanceSampleGGX(xi, roughness, N);
+ vec3 V = N;
+ vec3 L = normalize(2.0 * dot(V, H) * H - V);
- for(uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) {
- vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT);
+ float NdotL = clamp(dot(N, L), 0.0, 1.0);
- vec3 H = ImportanceSampleGGX( xi, roughness, N );
- vec3 V = N;
- vec3 L = normalize(2.0 * dot( V, H ) * H - V);
+ if (NdotL > 0.0) {
- float ndotl = clamp(dot(N, L),0.0,1.0);
-
- if (ndotl>0.0) {
#ifdef USE_SOURCE_PANORAMA
- sum.rgb += texturePanorama(H,source_panorama).rgb *ndotl;
-#endif
-
-#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
-
- sum.rgb += textureDualParaboloidArray(H).rgb *ndotl;
+ sum.rgb += texturePanorama(source_panorama, L).rgb * NdotL;
+#else
+ L.y = -L.y;
+ sum.rgb += textureCubeLod(source_cube, L, 0.0).rgb * NdotL;
#endif
-#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
- H.y=-H.y;
- sum.rgb += textureLod(source_cube, H, 0.0).rgb *ndotl;
-#endif
- sum.a += ndotl;
+ sum.a += NdotL;
}
}
- sum /= sum.a;
-
- frag_color = vec4(sum.rgb, 1.0);
-#endif
+ sum /= sum.a;
+ gl_FragColor = vec4(sum.rgb, 1.0);
}
-
diff --git a/drivers/gles2/shaders/effect_blur.glsl b/drivers/gles2/shaders/effect_blur.glsl
index b5f98a1244..a531802c75 100644
--- a/drivers/gles2/shaders/effect_blur.glsl
+++ b/drivers/gles2/shaders/effect_blur.glsl
@@ -1,8 +1,9 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
@@ -23,6 +24,7 @@ void main() {
#endif
}
+/* clang-format off */
[fragment]
#if !defined(GLES_OVER_GL)
@@ -30,6 +32,7 @@ precision mediump float;
#endif
in vec2 uv_interp;
+/* clang-format on */
uniform sampler2D source_color; //texunit:0
#ifdef SSAO_MERGE
@@ -39,7 +42,6 @@ uniform sampler2D source_ssao; //texunit:1
uniform float lod;
uniform vec2 pixel_size;
-
layout(location = 0) out vec4 frag_color;
#ifdef SSAO_MERGE
@@ -48,31 +50,31 @@ uniform vec4 ssao_color;
#endif
-#if defined (GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL)
+#if defined(GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL)
uniform float glow_strength;
#endif
-#if defined(DOF_FAR_BLUR) || defined (DOF_NEAR_BLUR)
+#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR)
#ifdef DOF_QUALITY_LOW
-const int dof_kernel_size=5;
-const int dof_kernel_from=2;
-const float dof_kernel[5] = float[] (0.153388,0.221461,0.250301,0.221461,0.153388);
+const int dof_kernel_size = 5;
+const int dof_kernel_from = 2;
+const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388);
#endif
#ifdef DOF_QUALITY_MEDIUM
-const int dof_kernel_size=11;
-const int dof_kernel_from=5;
-const float dof_kernel[11] = float[] (0.055037,0.072806,0.090506,0.105726,0.116061,0.119726,0.116061,0.105726,0.090506,0.072806,0.055037);
+const int dof_kernel_size = 11;
+const int dof_kernel_from = 5;
+const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037);
#endif
#ifdef DOF_QUALITY_HIGH
-const int dof_kernel_size=21;
-const int dof_kernel_from=10;
-const float dof_kernel[21] = float[] (0.028174,0.032676,0.037311,0.041944,0.046421,0.050582,0.054261,0.057307,0.059587,0.060998,0.061476,0.060998,0.059587,0.057307,0.054261,0.050582,0.046421,0.041944,0.037311,0.032676,0.028174);
+const int dof_kernel_size = 21;
+const int dof_kernel_from = 10;
+const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174);
#endif
uniform sampler2D dof_source_depth; //texunit:1
@@ -88,7 +90,6 @@ uniform sampler2D source_dof_original; //texunit:2
#endif
-
#ifdef GLOW_FIRST_PASS
uniform float exposure;
@@ -112,53 +113,51 @@ uniform float camera_z_near;
void main() {
-
-
#ifdef GAUSSIAN_HORIZONTAL
vec2 pix_size = pixel_size;
- pix_size*=0.5; //reading from larger buffer, so use more samples
- vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.214607;
- color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.189879;
- color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.157305;
- color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.071303;
- color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.189879;
- color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.157305;
- color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.071303;
+ pix_size *= 0.5; //reading from larger buffer, so use more samples
+ vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.214607;
+ color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.189879;
+ color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.157305;
+ color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.071303;
+ color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.189879;
+ color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.157305;
+ color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.071303;
frag_color = color;
#endif
#ifdef GAUSSIAN_VERTICAL
- vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pixel_size,lod )*0.38774;
- color+=textureLod( source_color, uv_interp+vec2( 0.0, 1.0)*pixel_size,lod )*0.24477;
- color+=textureLod( source_color, uv_interp+vec2( 0.0, 2.0)*pixel_size,lod )*0.06136;
- color+=textureLod( source_color, uv_interp+vec2( 0.0,-1.0)*pixel_size,lod )*0.24477;
- color+=textureLod( source_color, uv_interp+vec2( 0.0,-2.0)*pixel_size,lod )*0.06136;
+ vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.38774;
+ color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.24477;
+ color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.06136;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.24477;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.06136;
frag_color = color;
#endif
-//glow uses larger sigma for a more rounded blur effect
+ //glow uses larger sigma for a more rounded blur effect
#ifdef GLOW_GAUSSIAN_HORIZONTAL
vec2 pix_size = pixel_size;
- pix_size*=0.5; //reading from larger buffer, so use more samples
- vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.174938;
- color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.165569;
- color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.140367;
- color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.106595;
- color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.165569;
- color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.140367;
- color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.106595;
- color*=glow_strength;
+ pix_size *= 0.5; //reading from larger buffer, so use more samples
+ vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.174938;
+ color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.165569;
+ color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.140367;
+ color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.106595;
+ color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.165569;
+ color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.140367;
+ color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.106595;
+ color *= glow_strength;
frag_color = color;
#endif
#ifdef GLOW_GAUSSIAN_VERTICAL
- vec4 color =textureLod( source_color, uv_interp+vec2(0.0, 0.0)*pixel_size,lod )*0.288713;
- color+=textureLod( source_color, uv_interp+vec2(0.0, 1.0)*pixel_size,lod )*0.233062;
- color+=textureLod( source_color, uv_interp+vec2(0.0, 2.0)*pixel_size,lod )*0.122581;
- color+=textureLod( source_color, uv_interp+vec2(0.0,-1.0)*pixel_size,lod )*0.233062;
- color+=textureLod( source_color, uv_interp+vec2(0.0,-2.0)*pixel_size,lod )*0.122581;
- color*=glow_strength;
+ vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.288713;
+ color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.233062;
+ color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.122581;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581;
+ color *= glow_strength;
frag_color = color;
#endif
@@ -166,47 +165,45 @@ void main() {
vec4 color_accum = vec4(0.0);
- float depth = textureLod( dof_source_depth, uv_interp, 0.0).r;
+ float depth = textureLod(dof_source_depth, uv_interp, 0.0).r;
depth = depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif
- float amount = smoothstep(dof_begin,dof_end,depth);
- float k_accum=0.0;
+ float amount = smoothstep(dof_begin, dof_end, depth);
+ float k_accum = 0.0;
- for(int i=0;i<dof_kernel_size;i++) {
+ for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i-dof_kernel_from;
+ int int_ofs = i - dof_kernel_from;
vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius;
float tap_k = dof_kernel[i];
- float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r;
+ float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- tap_depth = ((tap_depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
#endif
- float tap_amount = mix(smoothstep(dof_begin,dof_end,tap_depth),1.0,int_ofs==0);
- tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect
-
- vec4 tap_color = textureLod( source_color, tap_uv, 0.0) * tap_k;
-
- k_accum+=tap_k*tap_amount;
- color_accum+=tap_color*tap_amount;
+ float tap_amount = mix(smoothstep(dof_begin, dof_end, tap_depth), 1.0, int_ofs == 0);
+ tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
+ vec4 tap_color = textureLod(source_color, tap_uv, 0.0) * tap_k;
+ k_accum += tap_k * tap_amount;
+ color_accum += tap_color * tap_amount;
}
- if (k_accum>0.0) {
- color_accum/=k_accum;
+ if (k_accum > 0.0) {
+ color_accum /= k_accum;
}
- frag_color = color_accum;///k_accum;
+ frag_color = color_accum; ///k_accum;
#endif
@@ -214,47 +211,45 @@ void main() {
vec4 color_accum = vec4(0.0);
- float max_accum=0;
+ float max_accum = 0;
- for(int i=0;i<dof_kernel_size;i++) {
+ for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i-dof_kernel_from;
+ int int_ofs = i - dof_kernel_from;
vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius;
- float ofs_influence = max(0.0,1.0-float(abs(int_ofs))/float(dof_kernel_from));
+ float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from));
float tap_k = dof_kernel[i];
- vec4 tap_color = textureLod( source_color, tap_uv, 0.0);
+ vec4 tap_color = textureLod(source_color, tap_uv, 0.0);
- float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r;
+ float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
-#ifdef USE_ORTHOGONAL_PROJECTION
- tap_depth = ((tap_depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+#ifdef USE_ORTHOGONAL_PROJECTION
+ tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
#endif
- float tap_amount = 1.0-smoothstep(dof_end,dof_begin,tap_depth);
- tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect
+ float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
+ tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
#ifdef DOF_NEAR_FIRST_TAP
- tap_color.a= 1.0-smoothstep(dof_end,dof_begin,tap_depth);
+ tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
#endif
- max_accum=max(max_accum,tap_amount*ofs_influence);
-
- color_accum+=tap_color*tap_k;
+ max_accum = max(max_accum, tap_amount * ofs_influence);
+ color_accum += tap_color * tap_k;
}
- color_accum.a=max(color_accum.a,sqrt(max_accum));
-
+ color_accum.a = max(color_accum.a, sqrt(max_accum));
#ifdef DOF_NEAR_BLUR_MERGE
- vec4 original = textureLod( source_dof_original, uv_interp, 0.0);
- color_accum = mix(original,color_accum,color_accum.a);
+ vec4 original = textureLod(source_dof_original, uv_interp, 0.0);
+ color_accum = mix(original, color_accum, color_accum.a);
#endif
@@ -265,37 +260,32 @@ void main() {
#endif
-
-
#ifdef GLOW_FIRST_PASS
#ifdef GLOW_USE_AUTO_EXPOSURE
- frag_color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey;
+ frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / auto_exposure_grey;
#endif
- frag_color*=exposure;
+ frag_color *= exposure;
- 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 );
+ 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;
#endif
-
#ifdef SIMPLE_COPY
- vec4 color =textureLod( source_color, uv_interp,0.0);
+ vec4 color = textureLod(source_color, uv_interp, 0.0);
frag_color = color;
#endif
#ifdef SSAO_MERGE
- vec4 color =textureLod( source_color, uv_interp,0.0);
- float ssao =textureLod( source_ssao, uv_interp,0.0).r;
+ vec4 color = textureLod(source_color, uv_interp, 0.0);
+ float ssao = textureLod(source_ssao, uv_interp, 0.0).r;
- frag_color = vec4( mix(color.rgb,color.rgb*mix(ssao_color.rgb,vec3(1.0),ssao),color.a), 1.0 );
+ frag_color = vec4(mix(color.rgb, color.rgb * mix(ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0);
#endif
-
-
}
diff --git a/drivers/gles2/shaders/exposure.glsl b/drivers/gles2/shaders/exposure.glsl
index 001b90a0f1..759adcda06 100644
--- a/drivers/gles2/shaders/exposure.glsl
+++ b/drivers/gles2/shaders/exposure.glsl
@@ -1,19 +1,19 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
void main() {
gl_Position = vertex_attrib;
-
}
+/* clang-format off */
[fragment]
-
uniform highp sampler2D source_exposure; //texunit:0
+/* clang-format on */
#ifdef EXPOSURE_BEGIN
@@ -33,66 +33,56 @@ uniform highp float max_luminance;
layout(location = 0) out highp float exposure;
-
-
void main() {
-
-
#ifdef EXPOSURE_BEGIN
-
- ivec2 src_pos = ivec2(gl_FragCoord.xy)*source_render_size/target_size;
+ ivec2 src_pos = ivec2(gl_FragCoord.xy) * source_render_size / target_size;
#if 1
//more precise and expensive, but less jittery
- ivec2 next_pos = ivec2(gl_FragCoord.xy+ivec2(1))*source_render_size/target_size;
- next_pos = max(next_pos,src_pos+ivec2(1)); //so it at least reads one pixel
- highp vec3 source_color=vec3(0.0);
- for(int i=src_pos.x;i<next_pos.x;i++) {
- for(int j=src_pos.y;j<next_pos.y;j++) {
- source_color += texelFetch(source_exposure,ivec2(i,j),0).rgb;
+ ivec2 next_pos = ivec2(gl_FragCoord.xy + ivec2(1)) * source_render_size / target_size;
+ next_pos = max(next_pos, src_pos + ivec2(1)); //so it at least reads one pixel
+ highp vec3 source_color = vec3(0.0);
+ for (int i = src_pos.x; i < next_pos.x; i++) {
+ for (int j = src_pos.y; j < next_pos.y; j++) {
+ source_color += texelFetch(source_exposure, ivec2(i, j), 0).rgb;
}
}
- source_color/=float( (next_pos.x-src_pos.x)*(next_pos.y-src_pos.y) );
+ source_color /= float((next_pos.x - src_pos.x) * (next_pos.y - src_pos.y));
#else
- highp vec3 source_color = texelFetch(source_exposure,src_pos,0).rgb;
+ highp vec3 source_color = texelFetch(source_exposure, src_pos, 0).rgb;
#endif
- exposure = max(source_color.r,max(source_color.g,source_color.b));
+ exposure = max(source_color.r, max(source_color.g, source_color.b));
#else
ivec2 coord = ivec2(gl_FragCoord.xy);
- exposure = texelFetch(source_exposure,coord*3+ivec2(0,0),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(1,0),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(2,0),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(0,1),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(1,1),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(2,1),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(0,2),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(1,2),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(2,2),0).r;
- exposure *= (1.0/9.0);
+ exposure = texelFetch(source_exposure, coord * 3 + ivec2(0, 0), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 0), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 0), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(0, 1), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 1), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 1), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(0, 2), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 2), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 2), 0).r;
+ exposure *= (1.0 / 9.0);
#ifdef EXPOSURE_END
#ifdef EXPOSURE_FORCE_SET
//will stay as is
#else
- highp float prev_lum = texelFetch(prev_exposure,ivec2(0,0),0).r; //1 pixel previous exposure
- exposure = clamp( prev_lum + (exposure-prev_lum)*exposure_adjust,min_luminance,max_luminance);
+ highp float prev_lum = texelFetch(prev_exposure, ivec2(0, 0), 0).r; //1 pixel previous exposure
+ exposure = clamp(prev_lum + (exposure - prev_lum) * exposure_adjust, min_luminance, max_luminance);
#endif //EXPOSURE_FORCE_SET
-
#endif //EXPOSURE_END
#endif //EXPOSURE_BEGIN
-
-
}
-
-
diff --git a/drivers/gles2/shaders/particles.glsl b/drivers/gles2/shaders/particles.glsl
index a62c124dfe..5974050fc1 100644
--- a/drivers/gles2/shaders/particles.glsl
+++ b/drivers/gles2/shaders/particles.glsl
@@ -1,14 +1,13 @@
+/* clang-format off */
[vertex]
-
-
-layout(location=0) in highp vec4 color;
-layout(location=1) in highp vec4 velocity_active;
-layout(location=2) in highp vec4 custom;
-layout(location=3) in highp vec4 xform_1;
-layout(location=4) in highp vec4 xform_2;
-layout(location=5) in highp vec4 xform_3;
-
+layout(location = 0) in highp vec4 color;
+/* clang-format on */
+layout(location = 1) in highp vec4 velocity_active;
+layout(location = 2) in highp vec4 custom;
+layout(location = 3) in highp vec4 xform_1;
+layout(location = 4) in highp vec4 xform_2;
+layout(location = 5) in highp vec4 xform_3;
struct Attractor {
@@ -39,7 +38,6 @@ uniform float lifetime;
uniform mat4 emission_transform;
uniform uint random_seed;
-
out highp vec4 out_color; //tfb:
out highp vec4 out_velocity_active; //tfb:
out highp vec4 out_custom; //tfb:
@@ -47,20 +45,24 @@ out highp vec4 out_xform_1; //tfb:
out highp vec4 out_xform_2; //tfb:
out highp vec4 out_xform_3; //tfb:
-
#if defined(USE_MATERIAL)
+/* clang-format off */
layout(std140) uniform UniformData { //ubo:0
MATERIAL_UNIFORMS
};
+/* clang-format on */
#endif
+/* clang-format off */
VERTEX_SHADER_GLOBALS
+/* clang-format on */
+
uint hash(uint x) {
x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
@@ -69,13 +71,12 @@ uint hash(uint x) {
return x;
}
-
void main() {
#ifdef PARTICLES_COPY
- out_color=color;
- out_velocity_active=velocity_active;
+ out_color = color;
+ out_velocity_active = velocity_active;
out_custom = custom;
out_xform_1 = xform_1;
out_xform_2 = xform_2;
@@ -83,34 +84,34 @@ void main() {
#else
- bool apply_forces=true;
- bool apply_velocity=true;
- float local_delta=delta;
+ bool apply_forces = true;
+ bool apply_velocity = true;
+ float local_delta = delta;
float mass = 1.0;
- float restart_phase = float(gl_VertexID)/float(total_particles);
+ float restart_phase = float(gl_VertexID) / float(total_particles);
- if (randomness>0.0) {
+ if (randomness > 0.0) {
uint seed = cycle;
if (restart_phase >= system_phase) {
- seed-=uint(1);
+ seed -= uint(1);
}
- seed*=uint(total_particles);
- seed+=uint(gl_VertexID);
+ seed *= uint(total_particles);
+ seed += uint(gl_VertexID);
float random = float(hash(seed) % uint(65536)) / 65536.0;
- restart_phase+=randomness * random * 1.0 / float(total_particles);
+ restart_phase += randomness * random * 1.0 / float(total_particles);
}
- restart_phase*= (1.0-explosiveness);
- bool restart=false;
+ restart_phase *= (1.0 - explosiveness);
+ bool restart = false;
bool shader_active = velocity_active.a > 0.5;
if (system_phase > prev_system_phase) {
// restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
- if (restart_phase >= prev_system_phase && restart_phase < system_phase ) {
- restart=true;
+ if (restart_phase >= prev_system_phase && restart_phase < system_phase) {
+ restart = true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (system_phase - restart_phase) * lifetime;
#endif
@@ -118,12 +119,12 @@ void main() {
} else {
if (restart_phase >= prev_system_phase) {
- restart=true;
+ restart = true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (1.0 - restart_phase + system_phase) * lifetime;
#endif
- } else if (restart_phase < system_phase ) {
- restart=true;
+ } else if (restart_phase < system_phase) {
+ restart = true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (system_phase - restart_phase) * lifetime;
#endif
@@ -133,14 +134,14 @@ void main() {
uint current_cycle = cycle;
if (system_phase < restart_phase) {
- current_cycle-=uint(1);
+ current_cycle -= uint(1);
}
uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID);
int index = int(gl_VertexID);
if (restart) {
- shader_active=emitting;
+ shader_active = emitting;
}
mat4 xform;
@@ -150,30 +151,33 @@ void main() {
#else
if (clear || restart) {
#endif
- out_color=vec4(1.0);
- out_velocity_active=vec4(0.0);
- out_custom=vec4(0.0);
+ out_color = vec4(1.0);
+ out_velocity_active = vec4(0.0);
+ out_custom = vec4(0.0);
if (!restart)
- shader_active=false;
+ shader_active = false;
xform = mat4(
- vec4(1.0,0.0,0.0,0.0),
- vec4(0.0,1.0,0.0,0.0),
- vec4(0.0,0.0,1.0,0.0),
- vec4(0.0,0.0,0.0,1.0)
- );
+ vec4(1.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 1.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
} else {
- out_color=color;
- out_velocity_active=velocity_active;
- out_custom=custom;
- xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0)));
+ out_color = color;
+ out_velocity_active = velocity_active;
+ out_custom = custom;
+ xform = transpose(mat4(xform_1, xform_2, xform_3, vec4(vec3(0.0), 1.0)));
}
if (shader_active) {
//execute shader
{
+ /* clang-format off */
+
VERTEX_SHADER_CODE
+
+ /* clang-format on */
}
#if !defined(DISABLE_FORCE)
@@ -181,26 +185,25 @@ VERTEX_SHADER_CODE
if (false) {
vec3 force = vec3(0.0);
- for(int i=0;i<attractor_count;i++) {
+ for (int i = 0; i < attractor_count; i++) {
vec3 rel_vec = xform[3].xyz - attractors[i].pos;
float dist = length(rel_vec);
if (attractors[i].radius < dist)
continue;
- if (attractors[i].eat_radius>0.0 && attractors[i].eat_radius > dist) {
- out_velocity_active.a=0.0;
+ if (attractors[i].eat_radius > 0.0 && attractors[i].eat_radius > dist) {
+ out_velocity_active.a = 0.0;
}
rel_vec = normalize(rel_vec);
- float attenuation = pow(dist / attractors[i].radius,attractors[i].attenuation);
+ float attenuation = pow(dist / attractors[i].radius, attractors[i].attenuation);
- if (attractors[i].dir==vec3(0.0)) {
+ if (attractors[i].dir == vec3(0.0)) {
//towards center
- force+=attractors[i].strength * rel_vec * attenuation * mass;
+ force += attractors[i].strength * rel_vec * attenuation * mass;
} else {
- force+=attractors[i].strength * attractors[i].dir * attenuation *mass;
-
+ force += attractors[i].strength * attractors[i].dir * attenuation * mass;
}
}
@@ -216,26 +219,25 @@ VERTEX_SHADER_CODE
}
#endif
} else {
- xform=mat4(0.0);
+ xform = mat4(0.0);
}
xform = transpose(xform);
- out_velocity_active.a = mix(0.0,1.0,shader_active);
+ out_velocity_active.a = mix(0.0, 1.0, shader_active);
out_xform_1 = xform[0];
out_xform_2 = xform[1];
out_xform_3 = xform[2];
#endif //PARTICLES_COPY
-
}
+/* clang-format off */
[fragment]
//any code here is never executed, stuff is filled just so it works
-
#if defined(USE_MATERIAL)
layout(std140) uniform UniformData {
@@ -249,12 +251,16 @@ MATERIAL_UNIFORMS
FRAGMENT_SHADER_GLOBALS
void main() {
-
{
+
LIGHT_SHADER_CODE
+
}
{
+
FRAGMENT_SHADER_CODE
+
}
}
+/* clang-format on */
diff --git a/drivers/gles2/shaders/resolve.glsl b/drivers/gles2/shaders/resolve.glsl
index 0b50a9c57b..5c6f5d6561 100644
--- a/drivers/gles2/shaders/resolve.glsl
+++ b/drivers/gles2/shaders/resolve.glsl
@@ -1,18 +1,19 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
-
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
}
+/* clang-format off */
[fragment]
#if !defined(GLES_OVER_GL)
@@ -20,6 +21,7 @@ precision mediump float;
#endif
in vec2 uv_interp;
+/* clang-format on */
uniform sampler2D source_specular; //texunit:0
uniform sampler2D source_ssr; //texunit:1
@@ -31,14 +33,12 @@ layout(location = 0) out vec4 frag_color;
void main() {
- vec4 specular = texture( source_specular, uv_interp );
+ vec4 specular = texture(source_specular, uv_interp);
#ifdef USE_SSR
-
- vec4 ssr = textureLod(source_ssr,uv_interp,0.0);
- specular.rgb = mix(specular.rgb,ssr.rgb*specular.a,ssr.a);
+ vec4 ssr = textureLod(source_ssr, uv_interp, 0.0);
+ specular.rgb = mix(specular.rgb, ssr.rgb * specular.a, ssr.a);
#endif
- frag_color = vec4(specular.rgb,1.0);
+ frag_color = vec4(specular.rgb, 1.0);
}
-
diff --git a/drivers/gles2/shaders/scene.glsl b/drivers/gles2/shaders/scene.glsl
index 79b989be4a..906c089170 100644
--- a/drivers/gles2/shaders/scene.glsl
+++ b/drivers/gles2/shaders/scene.glsl
@@ -1,940 +1,398 @@
+/* clang-format off */
[vertex]
-#define M_PI 3.14159265359
-
-/*
-from VisualServer:
-
-ARRAY_VERTEX=0,
-ARRAY_NORMAL=1,
-ARRAY_TANGENT=2,
-ARRAY_COLOR=3,
-ARRAY_TEX_UV=4,
-ARRAY_TEX_UV2=5,
-ARRAY_BONES=6,
-ARRAY_WEIGHTS=7,
-ARRAY_INDEX=8,
-*/
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
+#else
+precision mediump float;
+precision mediump int;
+#endif
-//hack to use uv if no uv present so it works with lightmap
+#include "stdlib.glsl"
+//
+// attributes
+//
-/* INPUT ATTRIBS */
+attribute highp vec4 vertex_attrib; // attrib:0
+/* clang-format on */
+attribute vec3 normal_attrib; // attrib:1
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=1) in vec3 normal_attrib;
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-layout(location=2) in vec4 tangent_attrib;
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
+attribute vec4 tangent_attrib; // attrib:2
#endif
-#if defined(ENABLE_COLOR_INTERP)
-layout(location=3) in vec4 color_attrib;
+#ifdef ENABLE_COLOR_INTERP
+attribute vec4 color_attrib; // attrib:3
#endif
-#if defined(ENABLE_UV_INTERP)
-layout(location=4) in vec2 uv_attrib;
+#ifdef ENABLE_UV_INTERP
+attribute vec2 uv_attrib; // attrib:4
#endif
-#if defined(ENABLE_UV2_INTERP)
-layout(location=5) in vec2 uv2_attrib;
+#ifdef ENABLE_UV2_INTERP
+attribute vec2 uv2_attrib; // attrib:5
#endif
-uniform float normal_mult;
-
#ifdef USE_SKELETON
-layout(location=6) in ivec4 bone_indices; // attrib:6
-layout(location=7) in vec4 bone_weights; // attrib:7
-#endif
-
-#ifdef USE_INSTANCING
-
-layout(location=8) in highp vec4 instance_xform0;
-layout(location=9) in highp vec4 instance_xform1;
-layout(location=10) in highp vec4 instance_xform2;
-layout(location=11) in lowp vec4 instance_color;
-
-#if defined(ENABLE_INSTANCE_CUSTOM)
-layout(location=12) in highp vec4 instance_custom_data;
-#endif
-
-#endif
-
-layout(std140) uniform SceneData { //ubo:0
-
- highp mat4 projection_matrix;
- highp mat4 inv_projection_matrix;
- highp mat4 camera_inverse_matrix;
- highp mat4 camera_matrix;
-
- mediump vec4 ambient_light_color;
- mediump vec4 bg_color;
-
- mediump vec4 fog_color_enabled;
- mediump vec4 fog_sun_color_amount;
-
- mediump float ambient_energy;
- mediump float bg_energy;
- mediump float z_offset;
- mediump float z_slope_scale;
- highp float shadow_dual_paraboloid_render_zfar;
- highp float shadow_dual_paraboloid_render_side;
+#ifdef USE_SKELETON_SOFTWARE
- highp vec2 viewport_size;
- highp vec2 screen_pixel_size;
- highp vec2 shadow_atlas_pixel_size;
- highp vec2 directional_shadow_pixel_size;
+attribute highp vec4 bone_transform_row_0; // attrib:9
+attribute highp vec4 bone_transform_row_1; // attrib:10
+attribute highp vec4 bone_transform_row_2; // attrib:11
- highp float time;
- highp float z_far;
- mediump float reflection_multiplier;
- mediump float subsurface_scatter_width;
- mediump float ambient_occlusion_affect_light;
-
- bool fog_depth_enabled;
- highp float fog_depth_begin;
- highp float fog_depth_curve;
- bool fog_transmit_enabled;
- highp float fog_transmit_curve;
- bool fog_height_enabled;
- highp float fog_height_min;
- highp float fog_height_max;
- highp float fog_height_curve;
-
-};
-
-uniform highp mat4 world_transform;
-
-
-#ifdef USE_LIGHT_DIRECTIONAL
+#else
-layout(std140) uniform DirectionalLightData { //ubo:3
+attribute vec4 bone_ids; // attrib:6
+attribute highp vec4 bone_weights; // attrib:7
- highp vec4 light_pos_inv_radius;
- mediump vec4 light_direction_attenuation;
- mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
- mediump vec4 light_clamp;
- mediump vec4 shadow_color_contact;
- highp mat4 shadow_matrix1;
- highp mat4 shadow_matrix2;
- highp mat4 shadow_matrix3;
- highp mat4 shadow_matrix4;
- mediump vec4 shadow_split_offsets;
-};
+uniform highp sampler2D bone_transforms; // texunit:-1
+uniform ivec2 skeleton_texture_size;
#endif
-#ifdef USE_VERTEX_LIGHTING
-//omni and spot
-
-struct LightData {
-
- highp vec4 light_pos_inv_radius;
- mediump vec4 light_direction_attenuation;
- mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
- mediump vec4 light_clamp;
- mediump vec4 shadow_color_contact;
- highp mat4 shadow_matrix;
-
-};
-
-
-layout(std140) uniform OmniLightData { //ubo:4
-
- LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
-};
-
-layout(std140) uniform SpotLightData { //ubo:5
-
- LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
-};
-
-#ifdef USE_FORWARD_LIGHTING
-
-
-uniform int omni_light_indices[MAX_FORWARD_LIGHTS];
-uniform int omni_light_count;
-
-uniform int spot_light_indices[MAX_FORWARD_LIGHTS];
-uniform int spot_light_count;
-
#endif
-out vec4 diffuse_light_interp;
-out vec4 specular_light_interp;
-
-void light_compute(vec3 N, vec3 L,vec3 V, vec3 light_color, float roughness, inout vec3 diffuse, inout vec3 specular) {
-
- float dotNL = max(dot(N,L), 0.0 );
- diffuse += dotNL * light_color / M_PI;
-
- if (roughness > 0.0) {
-
- vec3 H = normalize(V + L);
- float dotNH = max(dot(N,H), 0.0 );
- float intensity = pow( dotNH, (1.0-roughness) * 256.0);
- specular += light_color * intensity;
-
- }
-}
-
-void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal, float roughness,inout vec3 diffuse, inout vec3 specular) {
+#ifdef USE_INSTANCING
- vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex;
- float light_length = length( light_rel_vec );
- float normalized_distance = light_length*omni_lights[idx].light_pos_inv_radius.w;
- vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w ));
+attribute highp vec4 instance_xform_row_0; // attrib:12
+attribute highp vec4 instance_xform_row_1; // attrib:13
+attribute highp vec4 instance_xform_row_2; // attrib:14
- light_compute(normal,normalize(light_rel_vec),eye_vec,omni_lights[idx].light_color_energy.rgb * light_attenuation,roughness,diffuse,specular);
+attribute highp vec4 instance_color; // attrib:15
+attribute highp vec4 instance_custom_data; // attrib:8
-}
+#endif
-void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, inout vec3 diffuse, inout vec3 specular) {
+//
+// uniforms
+//
- vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz-vertex;
- float light_length = length( light_rel_vec );
- float normalized_distance = light_length*spot_lights[idx].light_pos_inv_radius.w;
- vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w ));
- vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz;
- float spot_cutoff=spot_lights[idx].light_params.y;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff);
- float spot_rim = (1.0 - scos) / (1.0 - spot_cutoff);
- light_attenuation *= 1.0 - pow( max(spot_rim,0.001), spot_lights[idx].light_params.x);
+uniform mat4 camera_matrix;
+uniform mat4 camera_inverse_matrix;
+uniform mat4 projection_matrix;
+uniform mat4 projection_inverse_matrix;
+uniform mat4 world_transform;
- light_compute(normal,normalize(light_rel_vec),eye_vec,spot_lights[idx].light_color_energy.rgb*light_attenuation,roughness,diffuse,specular);
-}
+uniform highp float time;
+uniform float normal_mult;
+#ifdef RENDER_DEPTH
+uniform float light_bias;
+uniform float light_normal_bias;
#endif
-/* Varyings */
+//
+// varyings
+//
-out highp vec3 vertex_interp;
-out vec3 normal_interp;
+varying highp vec3 vertex_interp;
+varying vec3 normal_interp;
-#if defined(ENABLE_COLOR_INTERP)
-out vec4 color_interp;
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
+varying vec3 tangent_interp;
+varying vec3 binormal_interp;
#endif
-#if defined(ENABLE_UV_INTERP)
-out vec2 uv_interp;
+#ifdef ENABLE_COLOR_INTERP
+varying vec4 color_interp;
#endif
-#if defined(ENABLE_UV2_INTERP)
-out vec2 uv2_interp;
+#ifdef ENABLE_UV_INTERP
+varying vec2 uv_interp;
#endif
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-out vec3 tangent_interp;
-out vec3 binormal_interp;
+#ifdef ENABLE_UV2_INTERP
+varying vec2 uv2_interp;
#endif
-
-
-
-
-#if defined(USE_MATERIAL)
-
-layout(std140) uniform UniformData { //ubo:1
-
-MATERIAL_UNIFORMS
-
-};
-
-#endif
+/* clang-format off */
VERTEX_SHADER_GLOBALS
-#ifdef RENDER_DEPTH_DUAL_PARABOLOID
-
-out highp float dp_clip;
-
-#endif
-
-#define SKELETON_TEXTURE_WIDTH 256
-
-#ifdef USE_SKELETON
-uniform highp sampler2D skeleton_texture; //texunit:-1
-#endif
-
-out highp vec4 position_interp;
-
-// FIXME: This triggers a Mesa bug that breaks rendering, so disabled for now.
-// See GH-13450 and https://bugs.freedesktop.org/show_bug.cgi?id=100316
-//invariant gl_Position;
+/* clang-format on */
void main() {
- highp vec4 vertex = vertex_attrib; // vec4(vertex_attrib.xyz * data_attrib.x,1.0);
+ highp vec4 vertex = vertex_attrib;
mat4 world_matrix = world_transform;
-
#ifdef USE_INSTANCING
-
{
- highp mat4 m=mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0));
+ highp mat4 m = mat4(
+ instance_xform_row_0,
+ instance_xform_row_1,
+ instance_xform_row_2,
+ vec4(0.0, 0.0, 0.0, 1.0));
world_matrix = world_matrix * transpose(m);
}
#endif
vec3 normal = normal_attrib * normal_mult;
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
vec3 tangent = tangent_attrib.xyz;
- tangent*=normal_mult;
+ tangent *= normal_mult;
float binormalf = tangent_attrib.a;
+ vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
-#if defined(ENABLE_COLOR_INTERP)
+#ifdef ENABLE_COLOR_INTERP
color_interp = color_attrib;
-#if defined(USE_INSTANCING)
+#ifdef USE_INSTANCING
color_interp *= instance_color;
#endif
+#endif
+#ifdef ENABLE_UV_INTERP
+ uv_interp = uv_attrib;
#endif
-#ifdef USE_SKELETON
- {
- //skeleton transform
- ivec2 tex_ofs = ivec2( bone_indices.x%256, (bone_indices.x/256)*3 );
- highp mat3x4 m = mat3x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
- ) * bone_weights.x;
+#ifdef ENABLE_UV2_INTERP
+ uv2_interp = uv2_attrib;
+#endif
- tex_ofs = ivec2( bone_indices.y%256, (bone_indices.y/256)*3 );
+#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
+ vertex = world_matrix * vertex;
+ normal = normalize((world_matrix * vec4(normal, 0.0)).xyz);
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
- m+= mat3x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
- ) * bone_weights.y;
+ tangent = normalize((world_matrix * vec4(tangent, 0.0)), xyz);
+ binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz);
+#endif
+#endif
- tex_ofs = ivec2( bone_indices.z%256, (bone_indices.z/256)*3 );
+#ifdef USE_SKELETON
- m+= mat3x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
- ) * bone_weights.z;
+ highp mat4 bone_transform = mat4(0.0);
+#ifdef USE_SKELETON_SOFTWARE
+ // passing the transform as attributes
- tex_ofs = ivec2( bone_indices.w%256, (bone_indices.w/256)*3 );
+ bone_transform[0] = vec4(bone_transform_row_0.x, bone_transform_row_1.x, bone_transform_row_2.x, 0.0);
+ bone_transform[1] = vec4(bone_transform_row_0.y, bone_transform_row_1.y, bone_transform_row_2.y, 0.0);
+ bone_transform[2] = vec4(bone_transform_row_0.z, bone_transform_row_1.z, bone_transform_row_2.z, 0.0);
+ bone_transform[3] = vec4(bone_transform_row_0.w, bone_transform_row_1.w, bone_transform_row_2.w, 1.0);
- m+= mat3x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
- ) * bone_weights.w;
+#else
+ // look up transform from the "pose texture"
+ {
+ for (int i = 0; i < 4; i++) {
+ ivec2 tex_ofs = ivec2(int(bone_ids[i]) * 3, 0);
- vertex.xyz = vertex * m;
+ highp mat4 b = mat4(
+ texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(0, 0)),
+ texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(1, 0)),
+ texel2DFetch(bone_transforms, skeleton_texture_size, tex_ofs + ivec2(2, 0)),
+ vec4(0.0, 0.0, 0.0, 1.0));
- normal = vec4(normal,0.0) * m;
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- tangent.xyz = vec4(tangent.xyz,0.0) * m;
-#endif
+ bone_transform += transpose(b) * bone_weights[i];
+ }
}
-#endif
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-
- vec3 binormal = normalize( cross(normal,tangent) * binormalf );
-#endif
-
-#if defined(ENABLE_UV_INTERP)
- uv_interp = uv_attrib;
#endif
-#if defined(ENABLE_UV2_INTERP)
- uv2_interp = uv2_attrib;
+ world_matrix = bone_transform * world_matrix;
#endif
-#if defined(USE_INSTANCING) && defined(ENABLE_INSTANCE_CUSTOM)
+#ifdef USE_INSTANCING
vec4 instance_custom = instance_custom_data;
#else
vec4 instance_custom = vec4(0.0);
-#endif
-
- highp mat4 modelview = camera_inverse_matrix * world_matrix;
- highp mat4 local_projection = projection_matrix;
-
-//using world coordinates
-#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
- vertex = world_matrix * vertex;
- normal = normalize((world_matrix * vec4(normal,0.0)).xyz);
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-
- tangent = normalize((world_matrix * vec4(tangent,0.0)).xyz);
- binormal = normalize((world_matrix * vec4(binormal,0.0)).xyz);
-#endif
#endif
- float roughness=0.0;
+ mat4 modelview = camera_matrix * world_matrix;
-//defines that make writing custom shaders easier
-#define projection_matrix local_projection
#define world_transform world_matrix
-{
-VERTEX_SHADER_CODE
+ {
+ /* clang-format off */
-}
+VERTEX_SHADER_CODE
+ /* clang-format on */
+ }
+ vec4 outvec = vertex;
-//using local coordinates (default)
+ // use local coordinates
#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
-
vertex = modelview * vertex;
- normal = normalize((modelview * vec4(normal,0.0)).xyz);
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+ normal = normalize((modelview * vec4(normal, 0.0)).xyz);
- tangent = normalize((modelview * vec4(tangent,0.0)).xyz);
- binormal = normalize((modelview * vec4(binormal,0.0)).xyz);
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
+ tangent = normalize((modelview * vec4(tangent, 0.0)).xyz);
+ binormal = normalize((modelview * vec4(binormal, 0.0)).xyz);
#endif
#endif
-//using world coordinates
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
-
- vertex = camera_inverse_matrix * vertex;
- normal = normalize((camera_inverse_matrix * vec4(normal,0.0)).xyz);
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-
- tangent = normalize((camera_inverse_matrix * vec4(tangent,0.0)).xyz);
- binormal = normalize((camera_inverse_matrix * vec4(binormal,0.0)).xyz);
+ vertex = camera_matrix * vertex;
+ normal = normalize((camera_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);
#endif
#endif
vertex_interp = vertex.xyz;
normal_interp = normal;
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
tangent_interp = tangent;
binormal_interp = binormal;
#endif
-
#ifdef RENDER_DEPTH
+ float z_ofs = light_bias;
+ z_ofs += (1.0 - abs(normal_interp.z)) * light_normal_bias;
-#ifdef RENDER_DEPTH_DUAL_PARABOLOID
-
- vertex_interp.z*= shadow_dual_paraboloid_render_side;
- normal_interp.z*= shadow_dual_paraboloid_render_side;
-
- dp_clip=vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
-
- //for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges
-
- highp vec3 vtx = vertex_interp+normalize(vertex_interp)*z_offset;
- highp float distance = length(vtx);
- vtx = normalize(vtx);
- vtx.xy/=1.0-vtx.z;
- vtx.z=(distance/shadow_dual_paraboloid_render_zfar);
- vtx.z=vtx.z * 2.0 - 1.0;
-
- vertex.xyz=vtx;
- vertex.w=1.0;
+ vertex_interp.z -= z_ofs;
-
-#else
-
- float z_ofs = z_offset;
- z_ofs += (1.0-abs(normal_interp.z))*z_slope_scale;
- vertex_interp.z-=z_ofs;
-
-#endif //RENDER_DEPTH_DUAL_PARABOLOID
-
-#endif //RENDER_DEPTH
-
- gl_Position = projection_matrix * vec4(vertex_interp,1.0);
-
- position_interp=gl_Position;
-
-#ifdef USE_VERTEX_LIGHTING
-
- diffuse_light_interp=vec4(0.0);
- specular_light_interp=vec4(0.0);
-
-#ifdef USE_FORWARD_LIGHTING
-
- for(int i=0;i<omni_light_count;i++) {
- light_process_omni(omni_light_indices[i],vertex_interp,-normalize( vertex_interp ),normal_interp,roughness,diffuse_light_interp.rgb,specular_light_interp.rgb);
- }
-
- for(int i=0;i<spot_light_count;i++) {
- light_process_spot(spot_light_indices[i],vertex_interp,-normalize( vertex_interp ),normal_interp,roughness,diffuse_light_interp.rgb,specular_light_interp.rgb);
- }
#endif
-#ifdef USE_LIGHT_DIRECTIONAL
-
- vec3 directional_diffuse = vec3(0.0);
- vec3 directional_specular = vec3(0.0);
- light_compute(normal_interp,-light_direction_attenuation.xyz,-normalize( vertex_interp ),light_color_energy.rgb,roughness,directional_diffuse,directional_specular);
-
- float diff_avg = dot(diffuse_light_interp.rgb,vec3(0.33333));
- float diff_dir_avg = dot(directional_diffuse,vec3(0.33333));
- if (diff_avg>0.0) {
- diffuse_light_interp.a=diff_dir_avg/(diff_avg+diff_dir_avg);
- } else {
- diffuse_light_interp.a=1.0;
- }
-
- diffuse_light_interp.rgb+=directional_diffuse;
-
- float spec_avg = dot(specular_light_interp.rgb,vec3(0.33333));
- float spec_dir_avg = dot(directional_specular,vec3(0.33333));
- if (spec_avg>0.0) {
- specular_light_interp.a=spec_dir_avg/(spec_avg+spec_dir_avg);
- } else {
- specular_light_interp.a=1.0;
- }
-
- specular_light_interp.rgb+=directional_specular;
-
-#endif //USE_LIGHT_DIRECTIONAL
-
-
-#endif // USE_VERTEX_LIGHTING
-
+ gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
}
-
+/* clang-format off */
[fragment]
+#extension GL_ARB_shader_texture_lod : enable
-/* texture unit usage, N is max_texture_unity-N
-
-1-skeleton
-2-radiance
-3-reflection_atlas
-4-directional_shadow
-5-shadow_atlas
-6-decal_atlas
-7-screen
-8-depth
-9-probe1
-10-probe2
-
-*/
-
-uniform highp mat4 world_transform;
-
-#define M_PI 3.14159265359
-
-/* Varyings */
-
-#if defined(ENABLE_COLOR_INTERP)
-in vec4 color_interp;
+#ifndef GL_ARB_shader_texture_lod
+#define texture2DLod(img, coord, lod) texture2D(img, coord)
+#define textureCubeLod(img, coord, lod) textureCube(img, coord)
#endif
-#if defined(ENABLE_UV_INTERP)
-in vec2 uv_interp;
-#endif
-
-#if defined(ENABLE_UV2_INTERP)
-in vec2 uv2_interp;
-#endif
-
-#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-in vec3 tangent_interp;
-in vec3 binormal_interp;
-#endif
-
-in highp vec3 vertex_interp;
-in vec3 normal_interp;
-
-
-/* PBR CHANNELS */
-
-//used on forward mainly
-uniform bool no_ambient_light;
-
-
-
-#ifdef USE_RADIANCE_MAP
-
-
-
-layout(std140) uniform Radiance { //ubo:2
-
- mat4 radiance_inverse_xform;
- float radiance_ambient_contribution;
-
-};
-
-#define RADIANCE_MAX_LOD 5.0
-
-#ifdef USE_RADIANCE_MAP_ARRAY
-
-uniform sampler2DArray radiance_map; //texunit:-2
-
-vec3 textureDualParaboloid(sampler2DArray p_tex, vec3 p_vec,float p_roughness) {
-
- vec3 norm = normalize(p_vec);
- norm.xy/=1.0+abs(norm.z);
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
-
- // we need to lie the derivatives (normg) and assume that DP side is always the same
- // to get proper texture filtering
- vec2 normg=norm.xy;
- if (norm.z>0.0) {
- norm.y=0.5-norm.y+0.5;
- }
-
- // thanks to OpenGL spec using floor(layer + 0.5) for texture arrays,
- // it's easy to have precision errors using fract() to interpolate layers
- // as such, using fixed point to ensure it works.
-
- float index = p_roughness * RADIANCE_MAX_LOD;
- int indexi = int(index * 256.0);
- vec3 base = textureGrad(p_tex, vec3(norm.xy, float(indexi/256)),dFdx(normg),dFdy(normg)).xyz;
- vec3 next = textureGrad(p_tex, vec3(norm.xy, float(indexi/256+1)),dFdx(normg),dFdy(normg)).xyz;
- return mix(base,next,float(indexi%256)/256.0);
-}
-
+#ifdef USE_GLES_OVER_GL
+#define mediump
+#define highp
#else
-
-uniform sampler2D radiance_map; //texunit:-2
-
-vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec,float p_roughness) {
-
- vec3 norm = normalize(p_vec);
- norm.xy/=1.0+abs(norm.z);
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
- if (norm.z>0.0) {
- norm.y=0.5-norm.y+0.5;
- }
- return textureLod(p_tex, norm.xy, p_roughness * RADIANCE_MAX_LOD).xyz;
-}
-
-#endif
-
-#endif
-
-/* Material Uniforms */
-
-
-
-#if defined(USE_MATERIAL)
-
-layout(std140) uniform UniformData {
-
-MATERIAL_UNIFORMS
-
-};
-
-#endif
-
-FRAGMENT_SHADER_GLOBALS
-
-layout(std140) uniform SceneData {
-
- highp mat4 projection_matrix;
- highp mat4 inv_projection_matrix;
- highp mat4 camera_inverse_matrix;
- highp mat4 camera_matrix;
-
- mediump vec4 ambient_light_color;
- mediump vec4 bg_color;
-
- mediump vec4 fog_color_enabled;
- mediump vec4 fog_sun_color_amount;
-
- mediump float ambient_energy;
- mediump float bg_energy;
-
- mediump float z_offset;
- mediump float z_slope_scale;
- highp float shadow_dual_paraboloid_render_zfar;
- highp float shadow_dual_paraboloid_render_side;
-
- highp vec2 viewport_size;
- highp vec2 screen_pixel_size;
- highp vec2 shadow_atlas_pixel_size;
- highp vec2 directional_shadow_pixel_size;
-
- highp float time;
- highp float z_far;
- mediump float reflection_multiplier;
- mediump float subsurface_scatter_width;
- mediump float ambient_occlusion_affect_light;
-
- bool fog_depth_enabled;
- highp float fog_depth_begin;
- highp float fog_depth_curve;
- bool fog_transmit_enabled;
- highp float fog_transmit_curve;
- bool fog_height_enabled;
- highp float fog_height_min;
- highp float fog_height_max;
- highp float fog_height_curve;
-};
-
-//directional light data
-
-#ifdef USE_LIGHT_DIRECTIONAL
-
-layout(std140) uniform DirectionalLightData {
-
- highp vec4 light_pos_inv_radius;
- mediump vec4 light_direction_attenuation;
- mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
- mediump vec4 light_clamp;
- mediump vec4 shadow_color_contact;
- highp mat4 shadow_matrix1;
- highp mat4 shadow_matrix2;
- highp mat4 shadow_matrix3;
- highp mat4 shadow_matrix4;
- mediump vec4 shadow_split_offsets;
-};
-
-
-uniform highp sampler2DShadow directional_shadow; //texunit:-4
-
-#endif
-
-#ifdef USE_VERTEX_LIGHTING
-in vec4 diffuse_light_interp;
-in vec4 specular_light_interp;
+precision mediump float;
+precision mediump int;
#endif
-//omni and spot
-
-struct LightData {
-
- highp vec4 light_pos_inv_radius;
- mediump vec4 light_direction_attenuation;
- mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
- mediump vec4 light_clamp;
- mediump vec4 shadow_color_contact;
- highp mat4 shadow_matrix;
-
-};
-
-
-layout(std140) uniform OmniLightData { //ubo:4
-
- LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
-};
-
-layout(std140) uniform SpotLightData { //ubo:5
-
- LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
-};
+#include "stdlib.glsl"
-uniform highp sampler2DShadow shadow_atlas; //texunit:-5
-
-
-struct ReflectionData {
-
- mediump vec4 box_extents;
- mediump vec4 box_offset;
- mediump vec4 params; // intensity, 0, interior , boxproject
- mediump vec4 ambient; //ambient color, energy
- mediump vec4 atlas_clamp;
- highp mat4 local_matrix; //up to here for spot and omni, rest is for directional
- //notes: for ambientblend, use distance to edge to blend between already existing global environment
-};
-
-layout(std140) uniform ReflectionProbeData { //ubo:6
-
- ReflectionData reflections[MAX_REFLECTION_DATA_STRUCTS];
-};
-uniform mediump sampler2D reflection_atlas; //texunit:-3
-
+#define M_PI 3.14159265359
-#ifdef USE_FORWARD_LIGHTING
+//
+// uniforms
+//
-uniform int omni_light_indices[MAX_FORWARD_LIGHTS];
-uniform int omni_light_count;
+uniform mat4 camera_matrix;
+/* clang-format on */
+uniform mat4 camera_inverse_matrix;
+uniform mat4 projection_matrix;
+uniform mat4 projection_inverse_matrix;
-uniform int spot_light_indices[MAX_FORWARD_LIGHTS];
-uniform int spot_light_count;
+uniform mat4 world_transform;
-uniform int reflection_indices[MAX_FORWARD_LIGHTS];
-uniform int reflection_count;
+uniform highp float time;
+#ifdef SCREEN_UV_USED
+uniform vec2 screen_pixel_size;
#endif
+uniform highp sampler2D depth_buffer; //texunit:-5
#if defined(SCREEN_TEXTURE_USED)
-
-uniform highp sampler2D screen_texture; //texunit:-7
-
+uniform highp sampler2D screen_texture; //texunit:-6
#endif
-#ifdef USE_MULTIPLE_RENDER_TARGETS
+#ifdef USE_RADIANCE_MAP
-layout(location=0) out vec4 diffuse_buffer;
-layout(location=1) out vec4 specular_buffer;
-layout(location=2) out vec4 normal_mr_buffer;
-#if defined(ENABLE_SSS)
-layout(location=3) out float sss_buffer;
-#endif
+#define RADIANCE_MAX_LOD 6.0
-#else
+uniform samplerCube radiance_map; // texunit:-2
-layout(location=0) out vec4 frag_color;
+uniform mat4 radiance_inverse_xform;
#endif
-in highp vec4 position_interp;
-uniform highp sampler2D depth_buffer; //texunit:-8
-
-#ifdef USE_CONTACT_SHADOWS
-
-float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) {
-
- if (abs(dir.z)>0.99)
- return 1.0;
-
- vec3 endpoint = pos+dir*max_distance;
- vec4 source = position_interp;
- vec4 dest = projection_matrix * vec4(endpoint, 1.0);
-
- vec2 from_screen = (source.xy / source.w) * 0.5 + 0.5;
- vec2 to_screen = (dest.xy / dest.w) * 0.5 + 0.5;
-
- vec2 screen_rel = to_screen - from_screen;
-
- if (length(screen_rel)<0.00001)
- return 1.0; //too small, don't do anything
+uniform float bg_energy;
- /*float pixel_size; //approximate pixel size
+uniform float ambient_sky_contribution;
+uniform vec4 ambient_color;
+uniform float ambient_energy;
- if (screen_rel.x > screen_rel.y) {
+#ifdef LIGHT_PASS
- pixel_size = abs((pos.x-endpoint.x)/(screen_rel.x/screen_pixel_size.x));
- } else {
- pixel_size = abs((pos.y-endpoint.y)/(screen_rel.y/screen_pixel_size.y));
+#define LIGHT_TYPE_DIRECTIONAL 0
+#define LIGHT_TYPE_OMNI 1
+#define LIGHT_TYPE_SPOT 2
- }*/
- vec4 bias = projection_matrix * vec4(pos+vec3(0.0,0.0,0.04), 1.0); //todo un-harcode the 0.04
+// general for all lights
+uniform int light_type;
+uniform float light_energy;
+uniform vec4 light_color;
+uniform float light_specular;
+// directional
+uniform vec3 light_direction;
- vec2 pixel_incr = normalize(screen_rel)*screen_pixel_size;
+// omni
+uniform vec3 light_position;
+uniform float light_range;
+uniform vec4 light_attenuation;
- float steps = length(screen_rel) / length(pixel_incr);
- steps = min(2000.0,steps); //put a limit to avoid freezing in some strange situation
- //steps=10.0;
+// spot
+uniform float light_spot_attenuation;
+uniform float light_spot_range;
+uniform float light_spot_angle;
- vec4 incr = (dest - source)/steps;
- float ratio=0.0;
- float ratio_incr = 1.0/steps;
+// shadows
+uniform highp sampler2D light_shadow_atlas; //texunit:-4
+uniform float light_has_shadow;
- while(steps>0.0) {
- source += incr*2.0;
- bias+=incr*2.0;
+uniform mat4 light_shadow_matrix;
+uniform vec4 light_clamp;
- vec3 uv_depth = (source.xyz / source.w) * 0.5 + 0.5;
- float depth = texture(depth_buffer,uv_depth.xy).r;
+// directional shadow
- if (depth < uv_depth.z) {
- if (depth > (bias.z/bias.w) * 0.5 + 0.5) {
- return min(pow(ratio,4.0),1.0);
- } else {
- return 1.0;
- }
- }
-
-
- ratio+=ratio_incr;
- steps-=1.0;
- }
-
- return 1.0;
-}
+uniform highp sampler2D light_directional_shadow; // texunit:-4
+uniform vec4 light_split_offsets;
+uniform mat4 light_shadow_matrix1;
+uniform mat4 light_shadow_matrix2;
+uniform mat4 light_shadow_matrix3;
+uniform mat4 light_shadow_matrix4;
#endif
-
-// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.
-// We're dividing this factor off because the overall term we'll end up looks like
-// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012):
-//
-// F(L.V) D(N.H) G(N.L) G(N.V) / (4 N.L N.V)
-//
-// We're basically regouping this as
//
-// F(L.V) D(N.H) [G(N.L)/(2 N.L)] [G(N.V) / (2 N.V)]
+// varyings
//
-// and thus, this function implements the [G(N.m)/(2 N.m)] part with m = L or V.
-//
-// The contents of the D and G (G1) functions (GGX) are taken from
-// E. Heitz, "Understanding the Masking-Shadowing Function in Microfacet-Based BRDFs", J. Comp. Graph. Tech. 3 (2) (2014).
-// Eqns 71-72 and 85-86 (see also Eqns 43 and 80).
-
-float G_GGX_2cos(float cos_theta_m, float alpha) {
- // Schlick's approximation
- // C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994)
- // Eq. (19), although see Heitz (2014) the about the problems with his derivation.
- // It nevertheless approximates GGX well with k = alpha/2.
- float k = 0.5*alpha;
- return 0.5 / (cos_theta_m * (1.0 - k) + k);
-
- // float cos2 = cos_theta_m*cos_theta_m;
- // float sin2 = (1.0-cos2);
- // return 1.0 /( cos_theta_m + sqrt(cos2 + alpha*alpha*sin2) );
-}
-float D_GGX(float cos_theta_m, float alpha) {
- float alpha2 = alpha*alpha;
- float d = 1.0 + (alpha2-1.0)*cos_theta_m*cos_theta_m;
- return alpha2/(M_PI * d * d);
-}
+varying highp vec3 vertex_interp;
+varying vec3 normal_interp;
-float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
- float cos2 = cos_theta_m * cos_theta_m;
- float sin2 = (1.0-cos2);
- float s_x = alpha_x * cos_phi;
- float s_y = alpha_y * sin_phi;
- return 1.0 / (cos_theta_m + sqrt(cos2 + (s_x*s_x + s_y*s_y)*sin2 ));
-}
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
+varying vec3 tangent_interp;
+varying vec3 binormal_interp;
+#endif
-float D_GGX_anisotropic(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
- float cos2 = cos_theta_m * cos_theta_m;
- float sin2 = (1.0-cos2);
- float r_x = cos_phi/alpha_x;
- float r_y = sin_phi/alpha_y;
- float d = cos2 + sin2*(r_x * r_x + r_y * r_y);
- return 1.0 / (M_PI * alpha_x * alpha_y * d * d );
-}
+#ifdef ENABLE_COLOR_INTERP
+varying vec4 color_interp;
+#endif
+#ifdef ENABLE_UV_INTERP
+varying vec2 uv_interp;
+#endif
-float SchlickFresnel(float u)
-{
- float m = 1.0-u;
- float m2 = m*m;
- return m2*m2*m; // pow(m,5)
-}
+#ifdef ENABLE_UV2_INTERP
+varying vec2 uv2_interp;
+#endif
-float GTR1(float NdotH, float a)
-{
- if (a >= 1.0) return 1.0/M_PI;
- float a2 = a*a;
- float t = 1.0 + (a2-1.0)*NdotH*NdotH;
- return (a2-1.0) / (M_PI*log(a2)*t);
-}
+varying vec3 view_interp;
vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) {
float dielectric = (0.034 * 2.0) * specular;
@@ -942,1172 +400,475 @@ vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) {
return mix(vec3(dielectric), albedo, metallic); // TODO: reference?
}
-void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light) {
-
-#if defined(USE_LIGHT_SHADER_CODE)
-//light is written by the light shader
-
- vec3 normal = N;
- vec3 albedo = diffuse_color;
- vec3 light = L;
- vec3 view = V;
-
-LIGHT_SHADER_CODE
+/* clang-format off */
+FRAGMENT_SHADER_GLOBALS
-#else
- float NdotL = dot(N,L);
- float cNdotL = max(NdotL, 0.0); // clamped NdotL
+/* clang-format on */
+
+#ifdef LIGHT_PASS
+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) {
+
+ float NdotL = dot(N, L);
+ float cNdotL = max(NdotL, 0.0);
float NdotV = dot(N, V);
float cNdotV = max(NdotV, 0.0);
- if (metallic < 1.0) {
-#if defined(DIFFUSE_OREN_NAYAR)
- vec3 diffuse_brdf_NL;
-#else
- float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
-#endif
-
-
-#if defined(DIFFUSE_LAMBERT_WRAP)
- //energy conserving lambert wrap shader
- diffuse_brdf_NL = max(0.0,(NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
-
-#elif defined(DIFFUSE_OREN_NAYAR)
-
- {
- // see http://mimosa-pudica.net/improved-oren-nayar.html
- float LdotV = dot(L, V);
-
-
- float s = LdotV - NdotL * NdotV;
- float t = mix(1.0, max(NdotL, NdotV), step(0.0, s));
-
- float sigma2 = roughness * roughness; // TODO: this needs checking
- vec3 A = 1.0 + sigma2 * (- 0.5 / (sigma2 + 0.33) + 0.17*diffuse_color / (sigma2 + 0.13) );
- float B = 0.45 * sigma2 / (sigma2 + 0.09);
-
- diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI);
- }
-
-#elif defined(DIFFUSE_TOON)
-
- diffuse_brdf_NL = smoothstep(-roughness,max(roughness,0.01),NdotL);
-
-#elif defined(DIFFUSE_BURLEY)
-
- {
-
-
- vec3 H = normalize(V + L);
- float cLdotH = max(0.0,dot(L, H));
+ {
+ // calculate diffuse reflection
- float FD90 = 0.5 + 2.0 * cLdotH * cLdotH * roughness;
- float FdV = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotV);
- float FdL = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotL);
- diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
- /*
- float energyBias = mix(roughness, 0.0, 0.5);
- float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
- float fd90 = energyBias + 2.0 * VoH * VoH * roughness;
- float f0 = 1.0;
- float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0);
- float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0);
+ // TODO hardcode Oren Nayar for now
+ float diffuse_brdf_NL;
- diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;*/
- }
-#else
- //lambert
- diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
-#endif
+ diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
+ // diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
-#if defined(TRANSMISSION_USED)
- diffuse_light += light_color * diffuse_color * mix(vec3(diffuse_brdf_NL), vec3(M_PI), transmission) * attenuation;
-#else
diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation;
-#endif
-
-
-
-#if defined(LIGHT_USE_RIM)
- float rim_light = pow(1.0-cNdotV, (1.0-roughness)*16.0);
- diffuse_light += rim_light * rim * mix(vec3(1.0),diffuse_color,rim_tint) * light_color;
-#endif
}
+ {
+ // calculate specular reflection
- if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
-
-
- // D
-
-#if defined(SPECULAR_BLINN)
-
- vec3 H = normalize(V + L);
- float cNdotH = max(dot(N,H), 0.0 );
- float intensity = pow( cNdotH, (1.0-roughness) * 256.0);
- specular_light += light_color * intensity * specular_blob_intensity * attenuation;
-
-#elif defined(SPECULAR_PHONG)
-
- vec3 R = normalize(-reflect(L,N));
- float cRdotV = max(0.0,dot(R,V));
- float intensity = pow( cRdotV, (1.0-roughness) * 256.0);
- specular_light += light_color * intensity * specular_blob_intensity * attenuation;
-
-#elif defined(SPECULAR_TOON)
-
- vec3 R = normalize(-reflect(L,N));
- float RdotV = dot(R,V);
- float mid = 1.0-roughness;
- mid*=mid;
- float intensity = smoothstep(mid-roughness*0.5, mid+roughness*0.5, RdotV) * mid;
- diffuse_light += light_color * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection
-
-#elif defined(SPECULAR_DISABLED)
- //none..
-
-#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 aspect = sqrt(1.0-anisotropy*0.9);
- float rx = roughness/aspect;
- float ry = roughness*aspect;
- float ax = rx*rx;
- float ay = ry*ry;
- float XdotH = dot( T, H );
- float YdotH = dot( B, H );
- float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
- float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH);
-
-# else
- float alpha = roughness * roughness;
- float D = D_GGX(cNdotH, alpha);
- float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha);
-# endif
- // F
- float F0 = 1.0; // FIXME
- float cLdotH5 = SchlickFresnel(cLdotH);
- float F = mix(cLdotH5, 1.0, F0);
-
- float 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);
-#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 specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL;
-
- specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation;
- }
-#endif
- }
-
-
-#endif //defined(USE_LIGHT_SHADER_CODE)
-}
-
-
-float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) {
-
-#ifdef SHADOW_MODE_PCF_13
-
- float avg=textureProj(shadow,vec4(pos,depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x*2.0,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x*2.0,0.0),depth,1.0));
- 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);
-
-#elif defined(SHADOW_MODE_PCF_5)
-
- float avg=textureProj(shadow,vec4(pos,depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0));
- return avg*(1.0/5.0);
-
-#else
-
- return textureProj(shadow,vec4(pos,depth,1.0));
-
-#endif
-
-}
-
-#ifdef RENDER_DEPTH_DUAL_PARABOLOID
-
-in highp float dp_clip;
-
-#endif
-
-
-
-#if 0
-//need to save texture depth for this
-
-vec3 light_transmittance(float translucency,vec3 light_vec, vec3 normal, vec3 pos, float distance) {
-
- float scale = 8.25 * (1.0 - translucency) / subsurface_scatter_width;
- float d = scale * distance;
-
- /**
- * Armed with the thickness, we can now calculate the color by means of the
- * precalculated transmittance profile.
- * (It can be precomputed into a texture, for maximum performance):
- */
- float dd = -d * d;
- vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
- vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
- vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
- vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
- vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
- vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
-
- /**
- * Using the profile, we finally approximate the transmitted lighting from
- * the back of the object:
- */
- return profile * clamp(0.3 + dot(light_vec, normal),0.0,1.0);
-}
-#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) {
-
- vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex;
- float light_length = length( light_rel_vec );
- float normalized_distance = light_length*omni_lights[idx].light_pos_inv_radius.w;
- vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w ));
-
- if (omni_lights[idx].light_params.w>0.5) {
- //there is a shadowmap
-
- highp vec3 splane=(omni_lights[idx].shadow_matrix * vec4(vertex,1.0)).xyz;
- float shadow_len=length(splane);
- splane=normalize(splane);
- vec4 clamp_rect=omni_lights[idx].light_clamp;
-
- if (splane.z>=0.0) {
-
- splane.z+=1.0;
-
- clamp_rect.y+=clamp_rect.w;
-
- } else {
-
- splane.z=1.0 - splane.z;
-
- /*
- if (clamp_rect.z<clamp_rect.w) {
- clamp_rect.x+=clamp_rect.z;
- } else {
- clamp_rect.y+=clamp_rect.w;
- }
- */
-
- }
-
- splane.xy/=splane.z;
- splane.xy=splane.xy * 0.5 + 0.5;
- splane.z = shadow_len * omni_lights[idx].light_pos_inv_radius.w;
-
- splane.xy = clamp_rect.xy+splane.xy*clamp_rect.zw;
- float shadow = sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,clamp_rect);
-
-#ifdef USE_CONTACT_SHADOWS
-
- if (shadow>0.01 && omni_lights[idx].shadow_color_contact.a>0.0) {
-
- float contact_shadow = contact_shadow_compute(vertex,normalize(light_rel_vec),min(light_length,omni_lights[idx].shadow_color_contact.a));
- shadow=min(shadow,contact_shadow);
-
- }
-#endif
- light_attenuation*=mix(omni_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow);
- }
-
- light_compute(normal,normalize(light_rel_vec),eye_vec,binormal,tangent,omni_lights[idx].light_color_energy.rgb,light_attenuation,albedo,transmission,omni_lights[idx].light_params.z*p_blob_intensity,roughness,metallic,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,diffuse_light,specular_light);
-
-}
-
-void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, vec3 binormal, vec3 tangent,vec3 albedo, vec3 transmission,float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss,float anisotropy,float p_blob_intensity, inout vec3 diffuse_light, inout vec3 specular_light) {
-
- vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz-vertex;
- float light_length = length( light_rel_vec );
- float normalized_distance = light_length*spot_lights[idx].light_pos_inv_radius.w;
- vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w ));
- vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz;
- float spot_cutoff=spot_lights[idx].light_params.y;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff);
- float spot_rim = (1.0 - scos) / (1.0 - spot_cutoff);
- light_attenuation *= 1.0 - pow( max(spot_rim,0.001), spot_lights[idx].light_params.x);
-
- if (spot_lights[idx].light_params.w>0.5) {
- //there is a shadowmap
- highp vec4 splane=(spot_lights[idx].shadow_matrix * vec4(vertex,1.0));
- splane.xyz/=splane.w;
-
- float shadow = sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,spot_lights[idx].light_clamp);
-
-#ifdef USE_CONTACT_SHADOWS
- if (shadow>0.01 && spot_lights[idx].shadow_color_contact.a>0.0) {
-
- float contact_shadow = contact_shadow_compute(vertex,normalize(light_rel_vec),min(light_length,spot_lights[idx].shadow_color_contact.a));
- shadow=min(shadow,contact_shadow);
-
- }
-#endif
- light_attenuation*=mix(spot_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow);
- }
-
- light_compute(normal,normalize(light_rel_vec),eye_vec,binormal,tangent,spot_lights[idx].light_color_energy.rgb,light_attenuation,albedo,transmission,spot_lights[idx].light_params.z*p_blob_intensity,roughness,metallic,rim,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) {
-
- vec3 ref_vec = normalize(reflect(vertex,normal));
- vec3 local_pos = (reflections[idx].local_matrix * vec4(vertex,1.0)).xyz;
- vec3 box_extents = reflections[idx].box_extents.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));
- //make blend more rounded
- blend=mix(length(inner_pos),blend,blend);
- blend*=blend;
- blend=1.001-blend;
-
- if (reflections[idx].params.x>0.0){// compute reflection
-
- vec3 local_ref_vec = (reflections[idx].local_matrix * vec4(ref_vec,0.0)).xyz;
-
- if (reflections[idx].params.w > 0.5) { //box project
-
- vec3 nrdir = normalize(local_ref_vec);
- vec3 rbmax = (box_extents - local_pos)/nrdir;
- vec3 rbmin = (-box_extents - local_pos)/nrdir;
-
-
- vec3 rbminmax = mix(rbmin,rbmax,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;
- local_ref_vec = posonbox - reflections[idx].box_offset.xyz;
- }
-
-
- vec4 clamp_rect=reflections[idx].atlas_clamp;
- vec3 norm = normalize(local_ref_vec);
- norm.xy/=1.0+abs(norm.z);
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
- if (norm.z>0.0) {
- norm.y=0.5-norm.y+0.5;
- }
-
- vec2 atlas_uv = norm.xy * clamp_rect.zw + clamp_rect.xy;
- atlas_uv = clamp(atlas_uv,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw);
-
- highp vec4 reflection;
- reflection.rgb = textureLod(reflection_atlas,atlas_uv,roughness*5.0).rgb;
-
- if (reflections[idx].params.z < 0.5) {
- reflection.rgb = mix(skybox,reflection.rgb,blend);
- }
- reflection.rgb*=reflections[idx].params.x;
- reflection.a = blend;
- reflection.rgb*=reflection.a;
-
- reflection_accum+=reflection;
- }
-
- if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox
-
-
- vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal,0.0)).xyz;
-
- vec3 splane=normalize(local_amb_vec);
- vec4 clamp_rect=reflections[idx].atlas_clamp;
-
- splane.z*=-1.0;
- if (splane.z>=0.0) {
- splane.z+=1.0;
- clamp_rect.y+=clamp_rect.w;
- } else {
- splane.z=1.0 - splane.z;
- splane.y=-splane.y;
- }
-
- splane.xy/=splane.z;
- splane.xy=splane.xy * 0.5 + 0.5;
-
- splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy;
- splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw);
-
- highp vec4 ambient_out;
- ambient_out.a=blend;
- ambient_out.rgb = textureLod(reflection_atlas,splane.xy,5.0).rgb;
- ambient_out.rgb=mix(reflections[idx].ambient.rgb,ambient_out.rgb,reflections[idx].ambient.a);
- if (reflections[idx].params.z < 0.5) {
- ambient_out.rgb = mix(ambient,ambient_out.rgb,blend);
- }
-
- ambient_out.rgb *= ambient_out.a;
- ambient_accum+=ambient_out;
- } else {
-
- highp vec4 ambient_out;
- ambient_out.a=blend;
- ambient_out.rgb=reflections[idx].ambient.rgb;
- if (reflections[idx].params.z < 0.5) {
- ambient_out.rgb = mix(ambient,ambient_out.rgb,blend);
- }
- ambient_out.rgb *= ambient_out.a;
- ambient_accum+=ambient_out;
-
- }
-}
-
-#ifdef USE_GI_PROBES
-
-uniform mediump sampler3D gi_probe1; //texunit:-9
-uniform highp mat4 gi_probe_xform1;
-uniform highp vec3 gi_probe_bounds1;
-uniform highp vec3 gi_probe_cell_size1;
-uniform highp float gi_probe_multiplier1;
-uniform highp float gi_probe_bias1;
-uniform highp float gi_probe_normal_bias1;
-uniform bool gi_probe_blend_ambient1;
-
-uniform mediump sampler3D gi_probe2; //texunit:-10
-uniform highp mat4 gi_probe_xform2;
-uniform highp vec3 gi_probe_bounds2;
-uniform highp vec3 gi_probe_cell_size2;
-uniform highp float gi_probe_multiplier2;
-uniform highp float gi_probe_bias2;
-uniform highp float gi_probe_normal_bias2;
-uniform bool gi_probe2_enabled;
-uniform bool gi_probe_blend_ambient2;
-
-vec3 voxel_cone_trace(mediump sampler3D probe, vec3 cell_size, vec3 pos, vec3 ambient, bool blend_ambient, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
-
- float dist = p_bias;//1.0; //dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0;
- float alpha=0.0;
- vec3 color = vec3(0.0);
-
- while(dist < max_distance && alpha < 0.95) {
- float diameter = max(1.0, 2.0 * tan_half_angle * dist);
- vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) );
- float a = (1.0 - alpha);
- color += scolor.rgb * a;
- alpha += a * scolor.a;
- dist += diameter * 0.5;
- }
-
- if (blend_ambient) {
- color.rgb = mix(ambient,color.rgb,min(1.0,alpha/0.95));
- }
-
- return color;
-}
-
-void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, vec3 ambient, vec3 environment, bool blend_ambient,float multiplier, mat3 normal_mtx,vec3 ref_vec, float roughness,float p_bias,float p_normal_bias, inout vec4 out_spec, inout vec4 out_diff) {
-
-
-
- vec3 probe_pos = (probe_xform * vec4(pos,1.0)).xyz;
- vec3 ref_pos = (probe_xform * vec4(pos+ref_vec,1.0)).xyz;
- ref_vec = normalize(ref_pos - probe_pos);
-
- probe_pos+=(probe_xform * vec4(normal_mtx[2],0.0)).xyz*p_normal_bias;
-
-/* out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0);
- out_diff.a = 1.0;
- return;*/
- //out_diff = vec4(textureLod(probe,probe_pos*cell_size,3.0).rgb,1.0);
- //return;
-
- //this causes corrupted pixels, i have no idea why..
- if (any(bvec2(any(lessThan(probe_pos,vec3(0.0))),any(greaterThan(probe_pos,bounds))))) {
- return;
- }
-
- //vec3 blendv = probe_pos/bounds * 2.0 - 1.0;
- //float blend = 1.001-max(blendv.x,max(blendv.y,blendv.z));
- float blend=1.0;
-
- float max_distance = length(bounds);
-
- //radiance
-#ifdef VCT_QUALITY_HIGH
-
-#define MAX_CONE_DIRS 6
- vec3 cone_dirs[MAX_CONE_DIRS] = 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)
- );
-
- float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
- float cone_angle_tan = 0.577;
- float min_ref_tan = 0.0;
-#else
-
-#define MAX_CONE_DIRS 4
-
- vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] (
- vec3(0.707107, 0, 0.707107),
- vec3(0, 0.707107, 0.707107),
- vec3(-0.707107, 0, 0.707107),
- vec3(0, -0.707107, 0.707107)
- );
-
- float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
- float cone_angle_tan = 0.98269;
- max_distance*=0.5;
- float min_ref_tan = 0.2;
-
-#endif
- vec3 light=vec3(0.0);
- for(int i=0;i<MAX_CONE_DIRS;i++) {
-
- vec3 dir = normalize( (probe_xform * vec4(pos + normal_mtx * cone_dirs[i],1.0)).xyz - probe_pos);
- light+=cone_weights[i] * voxel_cone_trace(probe,cell_size,probe_pos,ambient,blend_ambient,dir,cone_angle_tan,max_distance,p_bias);
-
+ vec3 R = normalize(-reflect(L, N));
+ float cRdotV = max(dot(R, V), 0.0);
+ float blob_intensity = pow(cRdotV, (1.0 - roughness) * 256.0);
+ specular_light += light_color * attenuation * blob_intensity * specular_blob_intensity;
}
-
- light*=multiplier;
-
- out_diff += vec4(light*blend,blend);
-
- //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);
-
- irr_light *= multiplier;
- //irr_light=vec3(0.0);
-
- out_spec += vec4(irr_light*blend,blend);
-
}
+// shadows
-void gi_probes_compute(vec3 pos, vec3 normal, float roughness, inout vec3 out_specular, inout vec3 out_ambient) {
-
- roughness = roughness * roughness;
-
- vec3 ref_vec = normalize(reflect(normalize(pos),normal));
-
- //find arbitrary tangent and bitangent, then build a matrix
- vec3 v0 = abs(normal.z) < 0.999 ? vec3(0, 0, 1) : vec3(0, 1, 0);
- vec3 tangent = normalize(cross(v0, normal));
- vec3 bitangent = normalize(cross(tangent, normal));
- mat3 normal_mat = mat3(tangent,bitangent,normal);
-
- vec4 diff_accum = vec4(0.0);
- vec4 spec_accum = vec4(0.0);
-
- vec3 ambient = out_ambient;
- out_ambient = vec3(0.0);
-
- vec3 environment = out_specular;
-
- out_specular = vec3(0.0);
-
- gi_probe_compute(gi_probe1,gi_probe_xform1,gi_probe_bounds1,gi_probe_cell_size1,pos,ambient,environment,gi_probe_blend_ambient1,gi_probe_multiplier1,normal_mat,ref_vec,roughness,gi_probe_bias1,gi_probe_normal_bias1,spec_accum,diff_accum);
-
- if (gi_probe2_enabled) {
-
- gi_probe_compute(gi_probe2,gi_probe_xform2,gi_probe_bounds2,gi_probe_cell_size2,pos,ambient,environment,gi_probe_blend_ambient2,gi_probe_multiplier2,normal_mat,ref_vec,roughness,gi_probe_bias2,gi_probe_normal_bias2,spec_accum,diff_accum);
- }
-
- if (diff_accum.a>0.0) {
- diff_accum.rgb/=diff_accum.a;
- }
-
- if (spec_accum.a>0.0) {
- spec_accum.rgb/=spec_accum.a;
- }
-
- out_specular+=spec_accum.rgb;
- out_ambient+=diff_accum.rgb;
+float sample_shadow(
+ highp sampler2D shadow,
+ vec2 shadow_pixel_size,
+ vec2 pos,
+ float depth,
+ vec4 clamp_rect) {
+ // vec4 depth_value = texture2D(shadow, pos);
+ // return depth_value.z;
+ return texture2DProj(shadow, vec4(pos, depth, 1.0)).r;
+ // return (depth_value.x + depth_value.y + depth_value.z + depth_value.w) / 4.0;
}
#endif
-
-
void main() {
-#ifdef RENDER_DEPTH_DUAL_PARABOLOID
-
- if (dp_clip>0.0)
- discard;
-#endif
-
- //lay out everything, whathever is unused is optimized away anyway
highp vec3 vertex = vertex_interp;
- vec3 albedo = vec3(0.8,0.8,0.8);
+ vec3 albedo = vec3(1.0);
vec3 transmission = vec3(0.0);
float metallic = 0.0;
float specular = 0.5;
- vec3 emission = vec3(0.0,0.0,0.0);
+ vec3 emission = vec3(0.0);
float roughness = 1.0;
float rim = 0.0;
float rim_tint = 0.0;
- float clearcoat=0.0;
- float clearcoat_gloss=0.0;
- float anisotropy = 1.0;
- vec2 anisotropy_flow = vec2(1.0,0.0);
-
-#if defined(ENABLE_AO)
- float ao=1.0;
- float ao_light_affect=0.0;
-#endif
+ float clearcoat = 0.0;
+ float clearcoat_gloss = 0.0;
+ float anisotropy = 0.0;
+ vec2 anisotropy_flow = vec2(1.0, 0.0);
float alpha = 1.0;
+ float side = 1.0;
-#ifdef METERIAL_DOUBLESIDED
- float side=float(gl_FrontFacing)*2.0-1.0;
-#else
- float side=1.0;
-#endif
-
-
-#if defined(ALPHA_SCISSOR_USED)
- float alpha_scissor = 0.5;
+#if defined(ENABLE_AO)
+ float ao = 1.0;
+ float ao_light_affect = 0.0;
#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;
+#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP)
+ vec3 binormal = normalize(binormal_interp) * side;
+ vec3 tangent = normalize(tangent_interp) * side;
#else
vec3 binormal = vec3(0.0);
vec3 tangent = vec3(0.0);
#endif
- vec3 normal = normalize(normal_interp)*side;
-
-#if defined(ENABLE_UV_INTERP)
- vec2 uv = uv_interp;
-#endif
-
-#if defined(ENABLE_UV2_INTERP)
- vec2 uv2 = uv2_interp;
-#endif
-
-#if defined(ENABLE_COLOR_INTERP)
- vec4 color = color_interp;
-#endif
+ vec3 normal = normalize(normal_interp) * side;
#if defined(ENABLE_NORMALMAP)
-
- vec3 normalmap = vec3(0.0);
+ vec3 normalmap = vec3(0.5);
#endif
+ float normaldepth = 1.0;
- float normaldepth=1.0;
-
-#if defined(SCREEN_UV_USED)
- vec2 screen_uv = gl_FragCoord.xy*screen_pixel_size;
+#ifdef ALPHA_SCISSOR_USED
+ float alpha_scissor = 0.5;
#endif
-#if defined (ENABLE_SSS)
- float sss_strength=0.0;
+#ifdef SCREEN_UV_USED
+ vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
#endif
-{
-
+ {
+ /* clang-format off */
FRAGMENT_SHADER_CODE
-}
-
-
-#if defined(ALPHA_SCISSOR_USED)
- if (alpha<alpha_scissor) {
- discard;
+ /* clang-format on */
}
-#endif
-#ifdef USE_OPAQUE_PREPASS
+#if defined(ENABLE_NORMALMAP)
+ normalmap.xy = normalmap.xy * 2.0 - 1.0;
+ normalmap.z = sqrt(max(0.0, 1.0 - dot(normalmap.xy, normalmap.xy)));
- if (alpha<0.99) {
- discard;
- }
+ // normal = normalize(mix(normal_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side;
+ normal = normalmap;
#endif
-#if defined(ENABLE_NORMALMAP)
+ normal = normalize(normal);
- normalmap.xy=normalmap.xy*2.0-1.0;
- normalmap.z=sqrt(1.0-dot(normalmap.xy,normalmap.xy)); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
+ vec3 N = normal;
- normal = normalize( mix(normal_interp,tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z,normaldepth) ) * side;
+ vec3 specular_light = vec3(0.0, 0.0, 0.0);
+ vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
-#endif
+ vec3 ambient_light = vec3(0.0, 0.0, 0.0);
-#if defined(LIGHT_USE_ANISOTROPY)
+ vec3 env_reflection_light = vec3(0.0, 0.0, 0.0);
- if (anisotropy>0.01) {
- //rotation matrix
- mat3 rot = mat3( tangent, binormal, normal );
- //make local to space
- tangent = normalize(rot * vec3(anisotropy_flow.x,anisotropy_flow.y,0.0));
- binormal = normalize(rot * vec3(-anisotropy_flow.y,anisotropy_flow.x,0.0));
- }
+ vec3 eye_position = -normalize(vertex_interp);
-#endif
-
-#ifdef ENABLE_CLIP_ALPHA
- if (albedo.a<0.99) {
- //used for doublepass and shadowmapping
+#ifdef ALPHA_SCISSOR_USED
+ if (alpha < alpha_scissor) {
discard;
}
#endif
-/////////////////////// LIGHTING //////////////////////////////
-
- //apply energy conservation
-
-#ifdef USE_VERTEX_LIGHTING
-
- vec3 specular_light = specular_light_interp.rgb;
- vec3 diffuse_light = diffuse_light_interp.rgb;
-#else
-
- vec3 specular_light = vec3(0.0,0.0,0.0);
- vec3 diffuse_light = vec3(0.0,0.0,0.0);
-
-#endif
+//
+// Lighting
+//
+#ifdef LIGHT_PASS
- vec3 ambient_light;
- vec3 env_reflection_light = vec3(0.0,0.0,0.0);
+ if (light_type == LIGHT_TYPE_OMNI) {
+ vec3 light_vec = light_position - vertex;
+ float light_length = length(light_vec);
- vec3 eye_vec = -normalize( vertex_interp );
+ float normalized_distance = light_length / light_range;
+ float omni_attenuation = pow(1.0 - normalized_distance, light_attenuation.w);
+ vec3 attenuation = vec3(omni_attenuation);
-#ifdef USE_RADIANCE_MAP
+ if (light_has_shadow > 0.5) {
+ highp vec3 splane = (light_shadow_matrix * vec4(vertex, 1.0)).xyz;
+ float shadow_len = length(splane);
- if (no_ambient_light) {
- ambient_light=vec3(0.0,0.0,0.0);
- } else {
- {
+ splane = normalize(splane);
- { //read radiance from dual paraboloid
+ vec4 clamp_rect = light_clamp;
- vec3 ref_vec = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n);
- ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz);
- vec3 radiance = textureDualParaboloid(radiance_map,ref_vec,roughness) * bg_energy;
- env_reflection_light = radiance;
+ if (splane.z >= 0.0) {
+ splane.z += 1.0;
+ clamp_rect.y += clamp_rect.w;
+ } else {
+ splane.z = 1.0 - splane.z;
}
- //no longer a cubemap
- //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y);
- }
+ splane.xy /= splane.z;
+ splane.xy = splane.xy * 0.5 + 0.5;
+ splane.z = shadow_len / light_range;
- {
+ splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
- vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz);
- vec3 env_ambient=textureDualParaboloid(radiance_map,ambient_dir,1.0) * bg_energy;
+ float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), splane.xy, splane.z, clamp_rect);
- ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);
- //ambient_light=vec3(0.0,0.0,0.0);
+ if (shadow > splane.z) {
+ } else {
+ attenuation = vec3(0.0);
+ }
}
- }
-
-#else
-
- if (no_ambient_light){
- ambient_light=vec3(0.0,0.0,0.0);
- } else {
- ambient_light=ambient_light_color.rgb;
- }
-#endif
-
- ambient_light*=ambient_energy;
-
- float specular_blob_intensity=1.0;
-#if defined(SPECULAR_TOON)
- specular_blob_intensity*=specular * 2.0;
-#endif
-
-#if defined(USE_LIGHT_DIRECTIONAL)
-
- vec3 light_attenuation=vec3(1.0);
- float depth_z = -vertex.z;
-#ifdef LIGHT_DIRECTIONAL_SHADOW
+ light_compute(
+ normal,
+ normalize(light_vec),
+ eye_position,
+ binormal,
+ tangent,
+ light_color.xyz * light_energy,
+ attenuation,
+ albedo,
+ transmission,
+ specular * light_specular,
+ roughness,
+ metallic,
+ rim,
+ rim_tint,
+ clearcoat,
+ clearcoat_gloss,
+ anisotropy,
+ diffuse_light,
+ specular_light);
+
+ } else if (light_type == LIGHT_TYPE_DIRECTIONAL) {
+
+ vec3 light_vec = -light_direction;
+ vec3 attenuation = vec3(1.0, 1.0, 1.0);
+
+ float depth_z = -vertex.z;
+
+ if (light_has_shadow > 0.5) {
#ifdef LIGHT_USE_PSSM4
- if (depth_z < shadow_split_offsets.w) {
+ if (depth_z < light_split_offsets.w) {
#elif defined(LIGHT_USE_PSSM2)
- if (depth_z < shadow_split_offsets.y) {
+ if (depth_z < light_split_offsets.y) {
#else
- if (depth_z < shadow_split_offsets.x) {
-#endif //LIGHT_USE_PSSM4
+ if (depth_z < light_split_offsets.x) {
+#endif
- vec3 pssm_coord;
- float pssm_fade=0.0;
+ vec3 pssm_coord;
+ float pssm_fade = 0.0;
#ifdef LIGHT_USE_PSSM_BLEND
- float pssm_blend;
- vec3 pssm_coord2;
- bool use_blend=true;
+ float pssm_blend;
+ vec3 pssm_coord2;
+ bool use_blend = true;
#endif
-
#ifdef LIGHT_USE_PSSM4
+ if (depth_z < light_split_offsets.y) {
+ if (depth_z < light_split_offsets.x) {
+ highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
+#ifdef LIGHT_USE_PSSM_BLEND
+ splane = (light_shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_coord2 = splane.xyz / splane.w;
- if (depth_z < shadow_split_offsets.y) {
-
- if (depth_z < shadow_split_offsets.x) {
-
- highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
-
-
-#if defined(LIGHT_USE_PSSM_BLEND)
-
- splane=(shadow_matrix2 * vec4(vertex,1.0));
- pssm_coord2=splane.xyz/splane.w;
- pssm_blend=smoothstep(0.0,shadow_split_offsets.x,depth_z);
+ pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
#endif
+ } else {
+ highp vec4 splane = (light_shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
- } else {
-
- highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
+#ifdef LIGHT_USE_PSSM_BLEND
+ splane = (light_shadow_matrix3 * vec4(vertex, 1.0));
+ pssm_coord2 = splane.xyz / splane.w;
-#if defined(LIGHT_USE_PSSM_BLEND)
- splane=(shadow_matrix3 * vec4(vertex,1.0));
- pssm_coord2=splane.xyz/splane.w;
- pssm_blend=smoothstep(shadow_split_offsets.x,shadow_split_offsets.y,depth_z);
+ pssm_blend = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
#endif
+ }
+ } else {
+ if (depth_z < light_split_offsets.z) {
- }
- } else {
-
-
- if (depth_z < shadow_split_offsets.z) {
-
- highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
+ highp vec4 splane = (light_shadow_matrix3 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
#if defined(LIGHT_USE_PSSM_BLEND)
- splane=(shadow_matrix4 * vec4(vertex,1.0));
- pssm_coord2=splane.xyz/splane.w;
- pssm_blend=smoothstep(shadow_split_offsets.y,shadow_split_offsets.z,depth_z);
+ splane = (light_shadow_matrix4 * vec4(vertex, 1.0));
+ pssm_coord2 = splane.xyz / splane.w;
+ pssm_blend = smoothstep(light_split_offsets.y, light_split_offsets.z, depth_z);
#endif
- } else {
+ } else {
- highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
- pssm_fade = smoothstep(shadow_split_offsets.z,shadow_split_offsets.w,depth_z);
+ highp vec4 splane = (light_shadow_matrix4 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
+ pssm_fade = smoothstep(light_split_offsets.z, light_split_offsets.w, depth_z);
#if defined(LIGHT_USE_PSSM_BLEND)
- use_blend=false;
-
+ use_blend = false;
#endif
+ }
+ }
- }
- }
-
-
-
-#endif //LIGHT_USE_PSSM4
+#endif // LIGHT_USE_PSSM4
#ifdef LIGHT_USE_PSSM2
+ if (depth_z < light_split_offsets.x) {
- if (depth_z < shadow_split_offsets.x) {
-
- highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
-
-
-#if defined(LIGHT_USE_PSSM_BLEND)
-
- splane=(shadow_matrix2 * vec4(vertex,1.0));
- pssm_coord2=splane.xyz/splane.w;
- pssm_blend=smoothstep(0.0,shadow_split_offsets.x,depth_z);
-#endif
-
- } else {
- highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
- pssm_fade = smoothstep(shadow_split_offsets.x,shadow_split_offsets.y,depth_z);
-#if defined(LIGHT_USE_PSSM_BLEND)
- use_blend=false;
+ highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
+#ifdef LIGHT_USE_PSSM_BLEND
+ splane = (light_shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_coord2 = splane.xyz / splane.w;
+ pssm_blend = smoothstep(0.0, light_split_offsets.x, depth_z);
+#endif
+ } else {
+ highp vec4 splane = (light_shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
+ pssm_fade = smoothstep(light_split_offsets.x, light_split_offsets.y, depth_z);
+#ifdef LIGHT_USE_PSSM_BLEND
+ use_blend = false;
#endif
+ }
- }
-
-#endif //LIGHT_USE_PSSM2
+#endif // LIGHT_USE_PSSM2
#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
- { //regular orthogonal
- highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
- }
-#endif
-
-
- //one one sample
-
- float shadow = sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp);
-
-#if defined(LIGHT_USE_PSSM_BLEND)
-
- if (use_blend) {
- shadow=mix(shadow, sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp),pssm_blend);
- }
+ {
+ highp vec4 splane = (light_shadow_matrix1 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
+ }
#endif
-#ifdef USE_CONTACT_SHADOWS
- if (shadow>0.01 && shadow_color_contact.a>0.0) {
+ float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord.xy, pssm_coord.z, light_clamp);
- float contact_shadow = contact_shadow_compute(vertex,-light_direction_attenuation.xyz,shadow_color_contact.a);
- shadow=min(shadow,contact_shadow);
-
- }
+#ifdef LIGHT_USE_PSSM_BLEND
+ if (use_blend) {
+ shadow = mix(shadow, sample_shadow(light_shadow_atlas, vec2(0.0), pssm_coord2.xy, pssm_coord2.z, light_clamp), pssm_blend);
+ }
#endif
- light_attenuation=mix(mix(shadow_color_contact.rgb,vec3(1.0),shadow),vec3(1.0),pssm_fade);
-
-
- }
+ attenuation *= shadow;
+ }
+ }
-#endif //LIGHT_DIRECTIONAL_SHADOW
-
-#ifdef USE_VERTEX_LIGHTING
- diffuse_light*=mix(vec3(1.0),light_attenuation,diffuse_light_interp.a);
- specular_light*=mix(vec3(1.0),light_attenuation,specular_light_interp.a);
+ light_compute(normal,
+ normalize(light_vec),
+ eye_position,
+ binormal,
+ tangent,
+ light_color.xyz * light_energy,
+ attenuation,
+ albedo,
+ transmission,
+ specular * light_specular,
+ roughness,
+ metallic,
+ rim,
+ rim_tint,
+ clearcoat,
+ clearcoat_gloss,
+ anisotropy,
+ diffuse_light,
+ specular_light);
+ } else if (light_type == LIGHT_TYPE_SPOT) {
+
+ vec3 light_att = vec3(1.0);
+
+ if (light_has_shadow > 0.5) {
+ highp vec4 splane = (light_shadow_matrix * vec4(vertex, 1.0));
+ splane.xyz /= splane.w;
+
+ float shadow = sample_shadow(light_shadow_atlas, vec2(0.0), splane.xy, splane.z, light_clamp);
+
+ if (shadow > splane.z) {
+ } else {
+ light_att = vec3(0.0);
+ }
+ }
+ vec3 light_rel_vec = light_position - vertex;
+ 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;
+
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff));
+
+ spot_attenuation *= 1.0 - pow(spot_rim, light_spot_attenuation);
+
+ light_att *= vec3(spot_attenuation);
+
+ light_compute(
+ normal,
+ normalize(light_rel_vec),
+ eye_position,
+ binormal,
+ tangent,
+ light_color.xyz * light_energy,
+ light_att,
+ albedo,
+ transmission,
+ specular * light_specular,
+ roughness,
+ metallic,
+ rim,
+ rim_tint,
+ clearcoat,
+ clearcoat_gloss,
+ anisotropy,
+ diffuse_light,
+ specular_light);
+ }
+
+ gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha);
#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);
-#endif
-
-
-#endif //#USE_LIGHT_DIRECTIONAL
-
-#ifdef USE_GI_PROBES
- gi_probes_compute(vertex,normal,roughness,env_reflection_light,ambient_light);
-
-#endif
-
-#ifdef USE_FORWARD_LIGHTING
-
-
- highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0);
- highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0);
- for(int i=0;i<reflection_count;i++) {
- reflection_process(reflection_indices[i],vertex,normal,binormal,tangent,roughness,anisotropy,ambient_light,env_reflection_light,reflection_accum,ambient_accum);
- }
- if (reflection_accum.a>0.0) {
- specular_light+=reflection_accum.rgb/reflection_accum.a;
- } else {
- specular_light+=env_reflection_light;
- }
-
- if (ambient_accum.a>0.0) {
- ambient_light+=ambient_accum.rgb/ambient_accum.a;
- }
-
-
-
-#ifdef USE_VERTEX_LIGHTING
+#ifdef RENDER_DEPTH
- diffuse_light*=albedo;
#else
- for(int i=0;i<omni_light_count;i++) {
- light_process_omni(omni_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,transmission,roughness,metallic,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,specular_blob_intensity,diffuse_light,specular_light);
- }
+#ifdef USE_RADIANCE_MAP
- 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);
- }
+ vec3 ref_vec = reflect(-eye_position, N);
+ ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz);
-#endif //USE_VERTEX_LIGHTING
+ ref_vec.z *= -1.0;
-#endif
+ env_reflection_light = textureCubeLod(radiance_map, ref_vec, roughness * RADIANCE_MAX_LOD).xyz * bg_energy;
+ {
+ vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz);
+ vec3 env_ambient = textureCubeLod(radiance_map, ambient_dir, RADIANCE_MAX_LOD).xyz * bg_energy;
+ ambient_light = mix(ambient_color.rgb, env_ambient, ambient_sky_contribution);
+ }
+ ambient_light *= ambient_energy;
-#ifdef RENDER_DEPTH
-//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
-#else
+ specular_light += env_reflection_light;
- specular_light*=reflection_multiplier;
- ambient_light*=albedo; //ambient must be multiplied by albedo at the end
+ ambient_light *= albedo;
#if defined(ENABLE_AO)
- ambient_light*=ao;
- ao_light_affect = mix(1.0,ao,ao_light_affect);
- specular_light*=ao_light_affect;
- diffuse_light*=ao_light_affect;
+ ambient_light *= ao;
+ ao_light_affect = mix(1.0, ao, ao_light_affect);
+ specular_light *= ao_light_affect;
+ diffuse_light *= ao_light_affect;
#endif
+ diffuse_light *= 1.0 - metallic;
+ ambient_light *= 1.0 - metallic;
+ // environment BRDF approximation
- //energy conservation
- diffuse_light *= 1.0-metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point
- ambient_light *= 1.0-metallic;
-
-
+ // TODO shadeless
{
-
-#if defined(DIFFUSE_TOON)
- //simplify for toon, as
- specular_light *= specular * metallic * albedo * 2.0;
-#else
- // Environment brdf approximation (Lazarov 2013)
- // see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
- const vec4 c1 = vec4( 1.0, 0.0425, 1.04, -0.04);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
vec4 r = roughness * c0 + c1;
- float ndotv = clamp(dot(normal,eye_vec),0.0,1.0);
- float a004 = min( r.x * r.x, exp2( -9.28 * ndotv ) ) * r.x + r.y;
- vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
+ float ndotv = clamp(dot(normal, eye_position), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo);
specular_light *= AB.x * specular_color + AB.y;
-#endif
-
}
- if (fog_color_enabled.a > 0.5) {
+ gl_FragColor = vec4(ambient_light + diffuse_light + specular_light, alpha);
+ // gl_FragColor = vec4(normal, 1.0);
- float fog_amount=0.0;
-
-
-
-#ifdef USE_LIGHT_DIRECTIONAL
-
- vec3 fog_color = mix( fog_color_enabled.rgb, fog_sun_color_amount.rgb,fog_sun_color_amount.a * pow(max( dot(normalize(vertex),-light_direction_attenuation.xyz), 0.0),8.0) );
#else
-
- vec3 fog_color = fog_color_enabled.rgb;
+ gl_FragColor = vec4(albedo, alpha);
#endif
+#endif // RENDER_DEPTH
- //apply fog
-
- if (fog_depth_enabled) {
-
- float fog_z = smoothstep(fog_depth_begin,z_far,length(vertex));
-
- fog_amount = pow(fog_z,fog_depth_curve);
- if (fog_transmit_enabled) {
- vec3 total_light = emission + ambient_light + specular_light + diffuse_light;
- float transmit = pow(fog_z,fog_transmit_curve);
- fog_color = mix(max(total_light,fog_color),fog_color,transmit);
- }
- }
-
- if (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));
- }
-
- float rev_amount = 1.0 - fog_amount;
-
-
- emission = emission * rev_amount + fog_color * fog_amount;
- ambient_light*=rev_amount;
- specular_light*rev_amount;
- diffuse_light*=rev_amount;
-
- }
-
-#ifdef USE_MULTIPLE_RENDER_TARGETS
-
-
-#ifdef SHADELESS
- diffuse_buffer=vec4(albedo.rgb,0.0);
- specular_buffer=vec4(0.0);
-
-#else
-
-#if defined(ENABLE_AO)
-
- float ambient_scale=0.0; // AO is supplied by material
-#else
- //approximate ambient scale for SSAO, since we will lack full ambient
- float max_emission=max(emission.r,max(emission.g,emission.b));
- float max_ambient=max(ambient_light.r,max(ambient_light.g,ambient_light.b));
- float max_diffuse=max(diffuse_light.r,max(diffuse_light.g,diffuse_light.b));
- float total_ambient = max_ambient+max_diffuse+max_emission;
- float ambient_scale = (total_ambient>0.0) ? (max_ambient+ambient_occlusion_affect_light*max_diffuse)/total_ambient : 0.0;
-#endif //ENABLE_AO
-
- diffuse_buffer=vec4(emission+diffuse_light+ambient_light,ambient_scale);
- specular_buffer=vec4(specular_light,metallic);
-
-#endif //SHADELESS
-
- normal_mr_buffer=vec4(normalize(normal)*0.5+0.5,roughness);
-
-#if defined (ENABLE_SSS)
- sss_buffer = sss_strength;
-#endif
-
-
-#else //USE_MULTIPLE_RENDER_TARGETS
-
-
-#ifdef SHADELESS
- frag_color=vec4(albedo,alpha);
-#else
- frag_color=vec4(emission+ambient_light+diffuse_light+specular_light,alpha);
-#endif //SHADELESS
-
-
-#endif //USE_MULTIPLE_RENDER_TARGETS
-
-
-
-#endif //RENDER_DEPTH
-
-
+#endif // lighting
}
diff --git a/drivers/gles2/shaders/screen_space_reflection.glsl b/drivers/gles2/shaders/screen_space_reflection.glsl
index b2e6f7a736..a11da10b61 100644
--- a/drivers/gles2/shaders/screen_space_reflection.glsl
+++ b/drivers/gles2/shaders/screen_space_reflection.glsl
@@ -1,8 +1,9 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
out vec2 pos_interp;
@@ -11,13 +12,14 @@ void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
- pos_interp.xy=gl_Position.xy;
+ pos_interp.xy = gl_Position.xy;
}
+/* clang-format off */
[fragment]
-
in vec2 uv_interp;
+/* clang-format on */
in vec2 pos_interp;
uniform sampler2D source_diffuse; //texunit:0
@@ -40,81 +42,70 @@ uniform float depth_tolerance;
uniform float distance_fade;
uniform float curve_fade_in;
-
layout(location = 0) out vec4 frag_color;
-
-vec2 view_to_screen(vec3 view_pos,out float w) {
- vec4 projected = projection * vec4(view_pos, 1.0);
- projected.xyz /= projected.w;
- projected.xy = projected.xy * 0.5 + 0.5;
- w=projected.w;
- return projected.xy;
+vec2 view_to_screen(vec3 view_pos, out float w) {
+ vec4 projected = projection * vec4(view_pos, 1.0);
+ projected.xyz /= projected.w;
+ projected.xy = projected.xy * 0.5 + 0.5;
+ w = projected.w;
+ return projected.xy;
}
-
-
#define M_PI 3.14159265359
void main() {
-
- ////
-
- vec4 diffuse = texture( source_diffuse, uv_interp );
- vec4 normal_roughness = texture( source_normal_roughness, uv_interp);
+ vec4 diffuse = texture(source_diffuse, uv_interp);
+ vec4 normal_roughness = texture(source_normal_roughness, uv_interp);
vec3 normal;
- normal = normal_roughness.xyz*2.0-1.0;
+ normal = normal_roughness.xyz * 2.0 - 1.0;
float roughness = normal_roughness.w;
- float depth_tex = texture(source_depth,uv_interp).r;
+ float depth_tex = texture(source_depth, uv_interp).r;
- vec4 world_pos = inverse_projection * vec4( uv_interp*2.0-1.0, depth_tex*2.0-1.0, 1.0 );
- vec3 vertex = world_pos.xyz/world_pos.w;
+ vec4 world_pos = inverse_projection * vec4(uv_interp * 2.0 - 1.0, depth_tex * 2.0 - 1.0, 1.0);
+ vec3 vertex = world_pos.xyz / world_pos.w;
vec3 view_dir = normalize(vertex);
vec3 ray_dir = normalize(reflect(view_dir, normal));
- if (dot(ray_dir,normal)<0.001) {
- frag_color=vec4(0.0);
+ if (dot(ray_dir, normal) < 0.001) {
+ frag_color = vec4(0.0);
return;
}
//ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0);
//ray_dir = normalize(vec3(1,1,-1));
-
////////////////
-
//make ray length and clip it against the near plane (don't want to trace beyond visible)
float ray_len = (vertex.z + ray_dir.z * camera_z_far) > -camera_z_near ? (-camera_z_near - vertex.z) / ray_dir.z : camera_z_far;
- vec3 ray_end = vertex + ray_dir*ray_len;
+ vec3 ray_end = vertex + ray_dir * ray_len;
float w_begin;
- vec2 vp_line_begin = view_to_screen(vertex,w_begin);
+ vec2 vp_line_begin = view_to_screen(vertex, w_begin);
float w_end;
- vec2 vp_line_end = view_to_screen( ray_end, w_end);
- vec2 vp_line_dir = vp_line_end-vp_line_begin;
+ vec2 vp_line_end = view_to_screen(ray_end, w_end);
+ vec2 vp_line_dir = vp_line_end - vp_line_begin;
//we need to interpolate w along the ray, to generate perspective correct reflections
- w_begin = 1.0/w_begin;
- w_end = 1.0/w_end;
+ w_begin = 1.0 / w_begin;
+ w_end = 1.0 / w_end;
+ float z_begin = vertex.z * w_begin;
+ float z_end = ray_end.z * w_end;
- float z_begin = vertex.z*w_begin;
- float z_end = ray_end.z*w_end;
-
- vec2 line_begin = vp_line_begin/pixel_size;
- vec2 line_dir = vp_line_dir/pixel_size;
+ vec2 line_begin = vp_line_begin / pixel_size;
+ vec2 line_dir = vp_line_dir / pixel_size;
float z_dir = z_end - z_begin;
float w_dir = w_end - w_begin;
-
// clip the line to the viewport edges
float scale_max_x = min(1.0, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x));
@@ -124,121 +115,109 @@ void main() {
float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y);
line_dir *= line_clip;
z_dir *= line_clip;
- w_dir *=line_clip;
+ w_dir *= line_clip;
//clip z and w advance to line advance
vec2 line_advance = normalize(line_dir); //down to pixel
- float step_size = length(line_advance)/length(line_dir);
- float z_advance = z_dir*step_size; // adapt z advance to line advance
- float w_advance = w_dir*step_size; // adapt w advance to line advance
+ float step_size = length(line_advance) / length(line_dir);
+ float z_advance = z_dir * step_size; // adapt z advance to line advance
+ float w_advance = w_dir * step_size; // adapt w advance to line advance
//make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice)
- float advance_angle_adj = 1.0/max(abs(line_advance.x),abs(line_advance.y));
- line_advance*=advance_angle_adj; // adapt z advance to line advance
- z_advance*=advance_angle_adj;
- w_advance*=advance_angle_adj;
+ float advance_angle_adj = 1.0 / max(abs(line_advance.x), abs(line_advance.y));
+ line_advance *= advance_angle_adj; // adapt z advance to line advance
+ z_advance *= advance_angle_adj;
+ w_advance *= advance_angle_adj;
vec2 pos = line_begin;
float z = z_begin;
float w = w_begin;
- float z_from=z/w;
- float z_to=z_from;
+ float z_from = z / w;
+ float z_to = z_from;
float depth;
- vec2 prev_pos=pos;
+ vec2 prev_pos = pos;
- bool found=false;
+ bool found = false;
- float steps_taken=0.0;
+ float steps_taken = 0.0;
- for(int i=0;i<num_steps;i++) {
+ for (int i = 0; i < num_steps; i++) {
- pos+=line_advance;
- z+=z_advance;
- w+=w_advance;
+ pos += line_advance;
+ z += z_advance;
+ w += w_advance;
//convert to linear depth
- depth = texture(source_depth, pos*pixel_size).r * 2.0 - 1.0;
+ depth = texture(source_depth, pos * pixel_size).r * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif
- depth=-depth;
+ depth = -depth;
z_from = z_to;
- z_to = z/w;
+ z_to = z / w;
- if (depth>z_to) {
+ if (depth > z_to) {
//if depth was surpassed
- if (depth<=max(z_to,z_from)+depth_tolerance) {
+ if (depth <= max(z_to, z_from) + depth_tolerance) {
//check the depth tolerance
- found=true;
+ found = true;
}
break;
}
- steps_taken+=1.0;
- prev_pos=pos;
+ steps_taken += 1.0;
+ prev_pos = pos;
}
-
-
-
if (found) {
- float margin_blend=1.0;
-
+ float margin_blend = 1.0;
- vec2 margin = vec2((viewport_size.x+viewport_size.y)*0.5*0.05); //make a uniform margin
- if (any(bvec4(lessThan(pos,-margin),greaterThan(pos,viewport_size+margin)))) {
+ vec2 margin = vec2((viewport_size.x + viewport_size.y) * 0.5 * 0.05); //make a uniform margin
+ if (any(bvec4(lessThan(pos, -margin), greaterThan(pos, viewport_size + margin)))) {
//clip outside screen + margin
- frag_color=vec4(0.0);
+ frag_color = vec4(0.0);
return;
}
{
//blend fading out towards external margin
- vec2 margin_grad = mix(pos-viewport_size,-pos,lessThan(pos,vec2(0.0)));
- margin_blend = 1.0-smoothstep(0.0,margin.x,max(margin_grad.x,margin_grad.y));
+ vec2 margin_grad = mix(pos - viewport_size, -pos, lessThan(pos, vec2(0.0)));
+ margin_blend = 1.0 - smoothstep(0.0, margin.x, max(margin_grad.x, margin_grad.y));
//margin_blend=1.0;
-
}
vec2 final_pos;
float grad;
- grad=steps_taken/float(num_steps);
- float initial_fade = curve_fade_in==0.0 ? 1.0 : pow(clamp(grad,0.0,1.0),curve_fade_in);
- float fade = pow(clamp(1.0-grad,0.0,1.0),distance_fade)*initial_fade;
- final_pos=pos;
-
-
-
-
-
-
+ grad = steps_taken / float(num_steps);
+ float initial_fade = curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), curve_fade_in);
+ float fade = pow(clamp(1.0 - grad, 0.0, 1.0), distance_fade) * initial_fade;
+ final_pos = pos;
#ifdef REFLECT_ROUGHNESS
-
vec4 final_color;
//if roughness is enabled, do screen space cone tracing
if (roughness > 0.001) {
///////////////////////////////////////////////////////////////////////////////////////
//use a blurred version (in consecutive mipmaps) of the screen to simulate roughness
- float gloss = 1.0-roughness;
+ float gloss = 1.0 - roughness;
float cone_angle = roughness * M_PI * 0.5;
vec2 cone_dir = final_pos - line_begin;
float cone_len = length(cone_dir);
cone_dir = normalize(cone_dir); //will be used normalized from now on
float max_mipmap = filter_mipmap_levels - 1.0;
- float gloss_mult=gloss;
+ float gloss_mult = gloss;
- float rem_alpha=1.0;
+ float rem_alpha = 1.0;
final_color = vec4(0.0);
- for(int i=0;i<7;i++) {
+ for (int i = 0; i < 7; i++) {
float op_len = 2.0 * tan(cone_angle) * cone_len; //opposite side of iso triangle
float radius;
@@ -258,30 +237,30 @@ void main() {
}
//find the place where screen must be sampled
- vec2 sample_pos = ( line_begin + cone_dir * (cone_len - radius) ) * pixel_size;
+ vec2 sample_pos = (line_begin + cone_dir * (cone_len - radius)) * pixel_size;
//radius is in pixels, so it's natural that log2(radius) maps to the right mipmap for the amount of pixels
- float mipmap = clamp( log2( radius ), 0.0, max_mipmap );
+ float mipmap = clamp(log2(radius), 0.0, max_mipmap);
//mipmap = max(mipmap-1.0,0.0);
//do sampling
vec4 sample_color;
{
- sample_color = textureLod(source_diffuse,sample_pos,mipmap);
+ sample_color = textureLod(source_diffuse, sample_pos, mipmap);
}
//multiply by gloss
- sample_color.rgb*=gloss_mult;
- sample_color.a=gloss_mult;
+ sample_color.rgb *= gloss_mult;
+ sample_color.a = gloss_mult;
rem_alpha -= sample_color.a;
- if(rem_alpha < 0.0) {
+ if (rem_alpha < 0.0) {
sample_color.rgb *= (1.0 - abs(rem_alpha));
}
- final_color+=sample_color;
+ final_color += sample_color;
- if (final_color.a>=0.95) {
+ if (final_color.a >= 0.95) {
// This code of accumulating gloss and aborting on near one
// makes sense when you think of cone tracing.
// Think of it as if roughness was 0, then we could abort on the first
@@ -290,29 +269,21 @@ void main() {
break;
}
- cone_len-=radius*2.0; //go to next (smaller) circle.
-
- gloss_mult*=gloss;
-
+ cone_len -= radius * 2.0; //go to next (smaller) circle.
+ gloss_mult *= gloss;
}
} else {
- final_color = textureLod(source_diffuse,final_pos*pixel_size,0.0);
+ final_color = textureLod(source_diffuse, final_pos * pixel_size, 0.0);
}
- frag_color = vec4(final_color.rgb,fade*margin_blend);
+ frag_color = vec4(final_color.rgb, fade * margin_blend);
#else
- frag_color = vec4(textureLod(source_diffuse,final_pos*pixel_size,0.0).rgb,fade*margin_blend);
+ frag_color = vec4(textureLod(source_diffuse, final_pos * pixel_size, 0.0).rgb, fade * margin_blend);
#endif
-
-
} else {
- frag_color = vec4(0.0,0.0,0.0,0.0);
+ frag_color = vec4(0.0, 0.0, 0.0, 0.0);
}
-
-
-
}
-
diff --git a/drivers/gles2/shaders/ssao.glsl b/drivers/gles2/shaders/ssao.glsl
index 219f0957e0..82eea8f274 100644
--- a/drivers/gles2/shaders/ssao.glsl
+++ b/drivers/gles2/shaders/ssao.glsl
@@ -1,14 +1,16 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
void main() {
gl_Position = vertex_attrib;
- gl_Position.z=1.0;
+ gl_Position.z = 1.0;
}
+/* clang-format off */
[fragment]
#define TWO_PI 6.283185307179586476925286766559
@@ -43,19 +45,21 @@ void main() {
// This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent
// taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9
-const int ROTATIONS[] = int[]( 1, 1, 2, 3, 2, 5, 2, 3, 2,
-3, 3, 5, 5, 3, 4, 7, 5, 5, 7,
-9, 8, 5, 5, 7, 7, 7, 8, 5, 8,
-11, 12, 7, 10, 13, 8, 11, 8, 7, 14,
-11, 11, 13, 12, 13, 19, 17, 13, 11, 18,
-19, 11, 11, 14, 17, 21, 15, 16, 17, 18,
-13, 17, 11, 17, 19, 18, 25, 18, 19, 19,
-29, 21, 19, 27, 31, 29, 21, 18, 17, 29,
-31, 31, 23, 18, 25, 26, 25, 23, 19, 34,
-19, 27, 21, 25, 39, 29, 17, 21, 27 );
+const int ROTATIONS[] = int[](
+ 1, 1, 2, 3, 2, 5, 2, 3, 2,
+ 3, 3, 5, 5, 3, 4, 7, 5, 5, 7,
+ 9, 8, 5, 5, 7, 7, 7, 8, 5, 8,
+ 11, 12, 7, 10, 13, 8, 11, 8, 7, 14,
+ 11, 11, 13, 12, 13, 19, 17, 13, 11, 18,
+ 19, 11, 11, 14, 17, 21, 15, 16, 17, 18,
+ 13, 17, 11, 17, 19, 18, 25, 18, 19, 19,
+ 29, 21, 19, 27, 31, 29, 21, 18, 17, 29,
+ 31, 31, 23, 18, 25, 26, 25, 23, 19, 34,
+ 19, 27, 21, 25, 39, 29, 17, 21, 27);
+/* clang-format on */
//#define NUM_SPIRAL_TURNS (7)
-const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES-1];
+const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES - 1];
uniform sampler2D source_depth; //texunit:0
uniform highp usampler2D source_depth_mipmaps; //texunit:1
@@ -90,44 +94,41 @@ vec3 reconstructCSPosition(vec2 S, float z) {
}
vec3 getPosition(ivec2 ssP) {
- vec3 P;
- P.z = texelFetch(source_depth, ssP, 0).r;
+ vec3 P;
+ P.z = texelFetch(source_depth, ssP, 0).r;
- P.z = P.z * 2.0 - 1.0;
+ P.z = P.z * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- P.z = ((P.z + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ P.z = ((P.z + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
- P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
+ P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
#endif
- P.z = -P.z;
+ P.z = -P.z;
- // Offset to pixel center
- P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
- return P;
+ // Offset to pixel center
+ P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
+ return P;
}
/** Reconstructs screen-space unit normal from screen-space position */
vec3 reconstructCSFaceNormal(vec3 C) {
- return normalize(cross(dFdy(C), dFdx(C)));
+ return normalize(cross(dFdy(C), dFdx(C)));
}
-
-
/** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */
-vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
- // Radius relative to ssR
- float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES));
- float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle;
+vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR) {
+ // Radius relative to ssR
+ float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES));
+ float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle;
- ssR = alpha;
- return vec2(cos(angle), sin(angle));
+ ssR = alpha;
+ return vec2(cos(angle), sin(angle));
}
-
/** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */
vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
- // Derivation:
- // mipLevel = floor(log(ssR / MAX_OFFSET));
+ // Derivation:
+ // mipLevel = floor(log(ssR / MAX_OFFSET));
int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
ivec2 ssP = ivec2(ssR * unitOffset) + ssC;
@@ -138,13 +139,12 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
// Manually clamp to the texture size because texelFetch bypasses the texture unit
ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), (screen_size >> mipLevel) - ivec2(1));
-
if (mipLevel < 1) {
//read from depth buffer
P.z = texelFetch(source_depth, mipP, 0).r;
P.z = P.z * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- P.z = ((P.z + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ P.z = ((P.z + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
@@ -153,78 +153,74 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
} else {
//read from mipmaps
- uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel-1).r;
- P.z = -(float(d)/65535.0)*camera_z_far;
+ uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel - 1).r;
+ P.z = -(float(d) / 65535.0) * camera_z_far;
}
-
// Offset to pixel center
P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
return P;
}
-
-
/** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds
- to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius
+ to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius
- Note that units of H() in the HPG12 paper are meters, not
- unitless. The whole falloff/sampling function is therefore
- unitless. In this implementation, we factor out (9 / radius).
+ Note that units of H() in the HPG12 paper are meters, not
+ unitless. The whole falloff/sampling function is therefore
+ unitless. In this implementation, we factor out (9 / radius).
- Four versions of the falloff function are implemented below
+ Four versions of the falloff function are implemented below
*/
-float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius,in float p_radius, in int tapIndex, in float randomPatternRotationAngle) {
- // Offset on the unit disk, spun for this pixel
- float ssR;
- vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
- ssR *= ssDiskRadius;
+float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in float p_radius, in int tapIndex, in float randomPatternRotationAngle) {
+ // Offset on the unit disk, spun for this pixel
+ float ssR;
+ vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
+ ssR *= ssDiskRadius;
- // The occluding point in camera space
- vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
+ // The occluding point in camera space
+ vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
- vec3 v = Q - C;
+ vec3 v = Q - C;
- float vv = dot(v, v);
- float vn = dot(v, n_C);
+ float vv = dot(v, v);
+ float vn = dot(v, n_C);
- const float epsilon = 0.01;
- float radius2 = p_radius*p_radius;
+ const float epsilon = 0.01;
+ float radius2 = p_radius * p_radius;
- // A: From the HPG12 paper
- // Note large epsilon to avoid overdarkening within cracks
- //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
+ // A: From the HPG12 paper
+ // Note large epsilon to avoid overdarkening within cracks
+ //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
- // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
- float f=max(radius2 - vv, 0.0);
- return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
+ // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
+ float f = max(radius2 - vv, 0.0);
+ return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
- // C: Medium contrast (which looks better at high radii), no division. Note that the
- // contribution still falls off with radius^2, but we've adjusted the rate in a way that is
- // more computationally efficient and happens to be aesthetically pleasing.
- // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
+ // C: Medium contrast (which looks better at high radii), no division. Note that the
+ // contribution still falls off with radius^2, but we've adjusted the rate in a way that is
+ // more computationally efficient and happens to be aesthetically pleasing.
+ // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
- // D: Low contrast, no division operation
- // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
+ // D: Low contrast, no division operation
+ // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
}
-
-
void main() {
-
// Pixel being shaded
ivec2 ssC = ivec2(gl_FragCoord.xy);
// World space point being shaded
vec3 C = getPosition(ssC);
-/* if (C.z <= -camera_z_far*0.999) {
- // We're on the skybox
- visibility=1.0;
- return;
- }*/
+ /*
+ if (C.z <= -camera_z_far*0.999) {
+ // We're on the skybox
+ visibility=1.0;
+ return;
+ }
+ */
//visibility=-C.z/camera_z_far;
//return;
@@ -251,7 +247,7 @@ void main() {
#endif
float sum = 0.0;
for (int i = 0; i < NUM_SAMPLES; ++i) {
- sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius,i, randomPatternRotationAngle);
+ sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius, i, randomPatternRotationAngle);
}
float A = max(0.0, 1.0 - sum * intensity_div_r6 * (5.0 / float(NUM_SAMPLES)));
@@ -271,10 +267,10 @@ void main() {
sum = 0.0;
for (int i = 0; i < NUM_SAMPLES; ++i) {
- sum += sampleAO(ssC, C, n_C, ssDiskRadius,radius2, i, randomPatternRotationAngle);
+ sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius2, i, randomPatternRotationAngle);
}
- A= min(A,max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / float(NUM_SAMPLES))));
+ A = min(A, max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / float(NUM_SAMPLES))));
#endif
// Bilateral box-filter over a quad for free, respecting depth edges
// (the difference that this makes is subtle)
@@ -286,8 +282,4 @@ void main() {
}
visibility = A;
-
}
-
-
-
diff --git a/drivers/gles2/shaders/ssao_blur.glsl b/drivers/gles2/shaders/ssao_blur.glsl
index 472dc21acf..e4133ad534 100644
--- a/drivers/gles2/shaders/ssao_blur.glsl
+++ b/drivers/gles2/shaders/ssao_blur.glsl
@@ -1,26 +1,25 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
void main() {
gl_Position = vertex_attrib;
- gl_Position.z=1.0;
+ gl_Position.z = 1.0;
}
+/* clang-format off */
[fragment]
-
uniform sampler2D source_ssao; //texunit:0
+/* clang-format on */
uniform sampler2D source_depth; //texunit:1
uniform sampler2D source_normal; //texunit:3
-
layout(location = 0) out float visibility;
-
//////////////////////////////////////////////////////////////////////////////////////////////
// Tunable Parameters:
@@ -28,32 +27,30 @@ layout(location = 0) out float visibility;
uniform float edge_sharpness;
/** Step in 2-pixel intervals since we already blurred against neighbors in the
- first AO pass. This constant can be increased while R decreases to improve
- performance at the expense of some dithering artifacts.
+ first AO pass. This constant can be increased while R decreases to improve
+ performance at the expense of some dithering artifacts.
- Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was
- unobjectionable after shading was applied but eliminated most temporal incoherence
- from using small numbers of sample taps.
- */
+ Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was
+ unobjectionable after shading was applied but eliminated most temporal incoherence
+ from using small numbers of sample taps.
+ */
uniform int filter_scale;
/** Filter radius in pixels. This will be multiplied by SCALE. */
-#define R (4)
-
+#define R (4)
//////////////////////////////////////////////////////////////////////////////////////////////
-
// Gaussian coefficients
const float gaussian[R + 1] =
-// float[](0.356642, 0.239400, 0.072410, 0.009869);
-// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0
- float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0
-// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0
+ //float[](0.356642, 0.239400, 0.072410, 0.009869);
+ //float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0
+ float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0
+//float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0
/** (1, 0) or (0, 1)*/
-uniform ivec2 axis;
+uniform ivec2 axis;
uniform float camera_z_far;
uniform float camera_z_near;
@@ -72,11 +69,11 @@ void main() {
float depth_divide = 1.0 / camera_z_far;
-// depth*=depth_divide;
+ //depth *= depth_divide;
/*
- if (depth > camera_z_far*0.999) {
- discard;//skybox
+ if (depth > camera_z_far * 0.999) {
+ discard; //skybox
}
*/
@@ -96,23 +93,21 @@ void main() {
if (r != 0) {
ivec2 ppos = ssC + axis * (r * filter_scale);
- float value = texelFetch(source_ssao, clamp(ppos,ivec2(0),clamp_limit), 0).r;
- ivec2 rpos = clamp(ppos,ivec2(0),clamp_limit);
+ float value = texelFetch(source_ssao, clamp(ppos, ivec2(0), clamp_limit), 0).r;
+ ivec2 rpos = clamp(ppos, ivec2(0), clamp_limit);
float temp_depth = texelFetch(source_depth, rpos, 0).r;
//vec3 temp_normal = texelFetch(source_normal, rpos, 0).rgb * 2.0 - 1.0;
temp_depth = temp_depth * 2.0 - 1.0;
temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near));
-// temp_depth *= depth_divide;
+ // temp_depth *= depth_divide;
// spatial domain: offset gaussian tap
float weight = 0.3 + gaussian[abs(r)];
//weight *= max(0.0,dot(temp_normal,normal));
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
- weight *= max(0.0, 1.0
- - edge_sharpness * abs(temp_depth - depth)
- );
+ weight *= max(0.0, 1.0 - edge_sharpness * abs(temp_depth - depth));
sum += value * weight;
totalWeight += weight;
diff --git a/drivers/gles2/shaders/ssao_minify.glsl b/drivers/gles2/shaders/ssao_minify.glsl
index 647c762438..272f3e236e 100644
--- a/drivers/gles2/shaders/ssao_minify.glsl
+++ b/drivers/gles2/shaders/ssao_minify.glsl
@@ -1,21 +1,23 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
void main() {
gl_Position = vertex_attrib;
}
+/* clang-format off */
[fragment]
-
#ifdef MINIFY_START
#define SDEPTH_TYPE highp sampler2D
uniform float camera_z_far;
uniform float camera_z_near;
+/* clang-format on */
#else
@@ -32,28 +34,23 @@ layout(location = 0) out mediump uint depth;
void main() {
-
ivec2 ssP = ivec2(gl_FragCoord.xy);
- // Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling.
- // On DX9, the bit-and can be implemented with floating-point modulo
+ // Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling.
+ // On DX9, the bit-and can be implemented with floating-point modulo
#ifdef MINIFY_START
float fdepth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r;
fdepth = fdepth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- fdepth = ((fdepth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ fdepth = ((fdepth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
fdepth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - fdepth * (camera_z_far - camera_z_near));
#endif
fdepth /= camera_z_far;
- depth = uint(clamp(fdepth*65535.0,0.0,65535.0));
+ depth = uint(clamp(fdepth * 65535.0, 0.0, 65535.0));
#else
depth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r;
#endif
-
-
}
-
-
diff --git a/drivers/gles2/shaders/stdlib.glsl b/drivers/gles2/shaders/stdlib.glsl
new file mode 100644
index 0000000000..6bc81a22d8
--- /dev/null
+++ b/drivers/gles2/shaders/stdlib.glsl
@@ -0,0 +1,37 @@
+
+vec2 select2(vec2 a, vec2 b, bvec2 c) {
+ vec2 ret;
+
+ ret.x = c.x ? b.x : a.x;
+ ret.y = c.y ? b.y : a.y;
+
+ return ret;
+}
+
+vec3 select3(vec3 a, vec3 b, bvec3 c) {
+ vec3 ret;
+
+ ret.x = c.x ? b.x : a.x;
+ ret.y = c.y ? b.y : a.y;
+ ret.z = c.z ? b.z : a.z;
+
+ return ret;
+}
+
+vec4 select4(vec4 a, vec4 b, bvec4 c) {
+ vec4 ret;
+
+ ret.x = c.x ? b.x : a.x;
+ ret.y = c.y ? b.y : a.y;
+ ret.z = c.z ? b.z : a.z;
+ ret.w = c.w ? b.w : a.w;
+
+ return ret;
+}
+
+highp vec4 texel2DFetch(highp sampler2D tex, ivec2 size, ivec2 coord) {
+ float x_coord = float(2 * coord.x + 1) / float(size.x * 2);
+ float y_coord = float(2 * coord.y + 1) / float(size.y * 2);
+
+ return texture2DLod(tex, vec2(x_coord, y_coord), 0.0);
+}
diff --git a/drivers/gles2/shaders/subsurf_scattering.glsl b/drivers/gles2/shaders/subsurf_scattering.glsl
index fc66d66198..f40fb3a244 100644
--- a/drivers/gles2/shaders/subsurf_scattering.glsl
+++ b/drivers/gles2/shaders/subsurf_scattering.glsl
@@ -1,105 +1,93 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
-
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
}
+/* clang-format off */
[fragment]
//#define QUALIFIER uniform // some guy on the interweb says it may be faster with this
#define QUALIFIER const
#ifdef USE_25_SAMPLES
-
-const int kernel_size=25;
-QUALIFIER vec2 kernel[25] = vec2[] (
- vec2(0.530605, 0.0),
- vec2(0.000973794, -3.0),
- vec2(0.00333804, -2.52083),
- vec2(0.00500364, -2.08333),
- vec2(0.00700976, -1.6875),
- vec2(0.0094389, -1.33333),
- vec2(0.0128496, -1.02083),
- vec2(0.017924, -0.75),
- vec2(0.0263642, -0.520833),
- vec2(0.0410172, -0.333333),
- vec2(0.0493588, -0.1875),
- vec2(0.0402784, -0.0833333),
- vec2(0.0211412, -0.0208333),
- vec2(0.0211412, 0.0208333),
- vec2(0.0402784, 0.0833333),
- vec2(0.0493588, 0.1875),
- vec2(0.0410172, 0.333333),
- vec2(0.0263642, 0.520833),
- vec2(0.017924, 0.75),
- vec2(0.0128496, 1.02083),
- vec2(0.0094389, 1.33333),
- vec2(0.00700976, 1.6875),
- vec2(0.00500364, 2.08333),
- vec2(0.00333804, 2.52083),
- vec2(0.000973794, 3.0)
-);
-
+const int kernel_size = 25;
+/* clang-format on */
+QUALIFIER vec2 kernel[25] = vec2[](
+ vec2(0.530605, 0.0),
+ vec2(0.000973794, -3.0),
+ vec2(0.00333804, -2.52083),
+ vec2(0.00500364, -2.08333),
+ vec2(0.00700976, -1.6875),
+ vec2(0.0094389, -1.33333),
+ vec2(0.0128496, -1.02083),
+ vec2(0.017924, -0.75),
+ vec2(0.0263642, -0.520833),
+ vec2(0.0410172, -0.333333),
+ vec2(0.0493588, -0.1875),
+ vec2(0.0402784, -0.0833333),
+ vec2(0.0211412, -0.0208333),
+ vec2(0.0211412, 0.0208333),
+ vec2(0.0402784, 0.0833333),
+ vec2(0.0493588, 0.1875),
+ vec2(0.0410172, 0.333333),
+ vec2(0.0263642, 0.520833),
+ vec2(0.017924, 0.75),
+ vec2(0.0128496, 1.02083),
+ vec2(0.0094389, 1.33333),
+ vec2(0.00700976, 1.6875),
+ vec2(0.00500364, 2.08333),
+ vec2(0.00333804, 2.52083),
+ vec2(0.000973794, 3.0));
#endif //USE_25_SAMPLES
#ifdef USE_17_SAMPLES
-
-const int kernel_size=17;
-
+const int kernel_size = 17;
QUALIFIER vec2 kernel[17] = vec2[](
- vec2(0.536343, 0.0),
- vec2(0.00317394, -2.0),
- vec2(0.0100386, -1.53125),
- vec2(0.0144609, -1.125),
- vec2(0.0216301, -0.78125),
- vec2(0.0347317, -0.5),
- vec2(0.0571056, -0.28125),
- vec2(0.0582416, -0.125),
- vec2(0.0324462, -0.03125),
- vec2(0.0324462, 0.03125),
- vec2(0.0582416, 0.125),
- vec2(0.0571056, 0.28125),
- vec2(0.0347317, 0.5),
- vec2(0.0216301, 0.78125),
- vec2(0.0144609, 1.125),
- vec2(0.0100386, 1.53125),
- vec2(0.00317394,2.0)
-);
-
+ vec2(0.536343, 0.0),
+ vec2(0.00317394, -2.0),
+ vec2(0.0100386, -1.53125),
+ vec2(0.0144609, -1.125),
+ vec2(0.0216301, -0.78125),
+ vec2(0.0347317, -0.5),
+ vec2(0.0571056, -0.28125),
+ vec2(0.0582416, -0.125),
+ vec2(0.0324462, -0.03125),
+ vec2(0.0324462, 0.03125),
+ vec2(0.0582416, 0.125),
+ vec2(0.0571056, 0.28125),
+ vec2(0.0347317, 0.5),
+ vec2(0.0216301, 0.78125),
+ vec2(0.0144609, 1.125),
+ vec2(0.0100386, 1.53125),
+ vec2(0.00317394, 2.0));
#endif //USE_17_SAMPLES
-
#ifdef USE_11_SAMPLES
-
-const int kernel_size=11;
-
+const int kernel_size = 11;
QUALIFIER vec2 kernel[11] = vec2[](
- vec2(0.560479, 0.0),
- vec2(0.00471691, -2.0),
- vec2(0.0192831, -1.28),
- vec2(0.03639, -0.72),
- vec2(0.0821904, -0.32),
- vec2(0.0771802, -0.08),
- vec2(0.0771802, 0.08),
- vec2(0.0821904, 0.32),
- vec2(0.03639, 0.72),
- vec2(0.0192831, 1.28),
- vec2(0.00471691,2.0)
-);
-
+ vec2(0.560479, 0.0),
+ vec2(0.00471691, -2.0),
+ vec2(0.0192831, -1.28),
+ vec2(0.03639, -0.72),
+ vec2(0.0821904, -0.32),
+ vec2(0.0771802, -0.08),
+ vec2(0.0771802, 0.08),
+ vec2(0.0821904, 0.32),
+ vec2(0.03639, 0.72),
+ vec2(0.0192831, 1.28),
+ vec2(0.00471691, 2.0));
#endif //USE_11_SAMPLES
-
-
uniform float max_radius;
uniform float camera_z_far;
uniform float camera_z_near;
@@ -115,28 +103,24 @@ layout(location = 0) out vec4 frag_color;
void main() {
- float strength = texture(source_sss,uv_interp).r;
- strength*=strength; //stored as sqrt
+ float strength = texture(source_sss, uv_interp).r;
+ strength *= strength; //stored as sqrt
// Fetch color of current pixel:
vec4 base_color = texture(source_diffuse, uv_interp);
-
- if (strength>0.0) {
-
+ if (strength > 0.0) {
// Fetch linear depth of current pixel:
float depth = texture(source_depth, uv_interp).r * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
float scale = unit_size; //remember depth is negative by default in OpenGL
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
float scale = unit_size / depth; //remember depth is negative by default in OpenGL
#endif
-
-
// Calculate the final step to fetch the surrounding pixels:
vec2 step = max_radius * scale * dir;
step *= strength; // Modulate it using the alpha channel.
@@ -157,35 +141,33 @@ void main() {
#ifdef ENABLE_FOLLOW_SURFACE
// If the difference in depth is huge, we lerp color back to "colorM":
- float depth_cmp = texture(source_depth, offset).r *2.0 - 1.0;
+ float depth_cmp = texture(source_depth, offset).r * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- depth_cmp = ((depth_cmp + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ depth_cmp = ((depth_cmp + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near));
#endif
- float s = clamp(300.0f * scale *
- max_radius * abs(depth - depth_cmp),0.0,1.0);
+ float s = clamp(300.0f * scale * max_radius * abs(depth - depth_cmp), 0.0, 1.0);
color = mix(color, base_color.rgb, s);
#endif
// Accumulate:
- color*=kernel[i].x;
+ color *= kernel[i].x;
#ifdef ENABLE_STRENGTH_WEIGHTING
float color_s = texture(source_sss, offset).r;
- color_weight+=color_s * kernel[i].x;
- color*=color_s;
+ color_weight += color_s * kernel[i].x;
+ color *= color_s;
#endif
color_accum += color;
-
}
#ifdef ENABLE_STRENGTH_WEIGHTING
- color_accum/=color_weight;
+ color_accum /= color_weight;
#endif
- frag_color = vec4(color_accum,base_color.a); //keep alpha (used for SSAO)
+ frag_color = vec4(color_accum, base_color.a); //keep alpha (used for SSAO)
} else {
frag_color = base_color;
}
diff --git a/drivers/gles2/shaders/tonemap.glsl b/drivers/gles2/shaders/tonemap.glsl
index 2f671158b2..eae3b5a1ca 100644
--- a/drivers/gles2/shaders/tonemap.glsl
+++ b/drivers/gles2/shaders/tonemap.glsl
@@ -1,8 +1,9 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
@@ -11,19 +12,19 @@ void main() {
gl_Position = vertex_attrib;
uv_interp = uv_in;
#ifdef V_FLIP
- uv_interp.y = 1.0-uv_interp.y;
+ uv_interp.y = 1.0 - uv_interp.y;
#endif
-
}
+/* clang-format off */
[fragment]
#if !defined(GLES_OVER_GL)
precision mediump float;
#endif
-
in vec2 uv_interp;
+/* clang-format on */
uniform highp sampler2D source; //texunit:0
@@ -56,64 +57,54 @@ uniform sampler2D color_correction; //texunit:3
#endif
-
layout(location = 0) out vec4 frag_color;
#ifdef USE_GLOW_FILTER_BICUBIC
// w0, w1, w2, and w3 are the four cubic B-spline basis functions
-float w0(float a)
-{
- return (1.0/6.0)*(a*(a*(-a + 3.0) - 3.0) + 1.0);
+float w0(float a) {
+ return (1.0 / 6.0) * (a * (a * (-a + 3.0) - 3.0) + 1.0);
}
-float w1(float a)
-{
- return (1.0/6.0)*(a*a*(3.0*a - 6.0) + 4.0);
+float w1(float a) {
+ return (1.0 / 6.0) * (a * a * (3.0 * a - 6.0) + 4.0);
}
-float w2(float a)
-{
- return (1.0/6.0)*(a*(a*(-3.0*a + 3.0) + 3.0) + 1.0);
+float w2(float a) {
+ return (1.0 / 6.0) * (a * (a * (-3.0 * a + 3.0) + 3.0) + 1.0);
}
-float w3(float a)
-{
- return (1.0/6.0)*(a*a*a);
+float w3(float a) {
+ return (1.0 / 6.0) * (a * a * a);
}
// g0 and g1 are the two amplitude functions
-float g0(float a)
-{
- return w0(a) + w1(a);
+float g0(float a) {
+ return w0(a) + w1(a);
}
-float g1(float a)
-{
- return w2(a) + w3(a);
+float g1(float a) {
+ return w2(a) + w3(a);
}
// h0 and h1 are the two offset functions
-float h0(float a)
-{
- return -1.0 + w1(a) / (w0(a) + w1(a));
+float h0(float a) {
+ return -1.0 + w1(a) / (w0(a) + w1(a));
}
-float h1(float a)
-{
- return 1.0 + w3(a) / (w2(a) + w3(a));
+float h1(float a) {
+ return 1.0 + w3(a) / (w2(a) + w3(a));
}
uniform ivec2 glow_texture_size;
-vec4 texture2D_bicubic(sampler2D tex, vec2 uv,int p_lod)
-{
- float lod=float(p_lod);
+vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) {
+ float lod = float(p_lod);
vec2 tex_size = vec2(glow_texture_size >> p_lod);
- vec2 pixel_size =1.0/tex_size;
- uv = uv*tex_size + 0.5;
- vec2 iuv = floor( uv );
- vec2 fuv = fract( uv );
+ vec2 pixel_size = 1.0 / tex_size;
+ uv = uv * tex_size + 0.5;
+ vec2 iuv = floor(uv);
+ vec2 fuv = fract(uv);
float g0x = g0(fuv.x);
float g1x = g1(fuv.x);
@@ -127,24 +118,19 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv,int p_lod)
vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - 0.5) * pixel_size;
vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - 0.5) * pixel_size;
- return g0(fuv.y) * (g0x * textureLod(tex, p0,lod) +
- g1x * textureLod(tex, p1,lod)) +
- g1(fuv.y) * (g0x * textureLod(tex, p2,lod) +
- g1x * textureLod(tex, p3,lod));
+ return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) +
+ (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod)));
}
-
-
-#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) texture2D_bicubic(m_tex,m_uv,m_lod)
+#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod)
#else
-#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) textureLod(m_tex,m_uv,float(m_lod))
+#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod))
#endif
-
-vec3 tonemap_filmic(vec3 color,float white) {
+vec3 tonemap_filmic(vec3 color, float white) {
float A = 0.15;
float B = 0.50;
@@ -154,11 +140,10 @@ vec3 tonemap_filmic(vec3 color,float white) {
float F = 0.30;
float W = 11.2;
- vec3 coltn = ((color*(A*color+C*B)+D*E)/(color*(A*color+B)+D*F))-E/F;
- float whitetn = ((white*(A*white+C*B)+D*E)/(white*(A*white+B)+D*F))-E/F;
-
- return coltn/whitetn;
+ vec3 coltn = ((color * (A * color + C * B) + D * E) / (color * (A * color + B) + D * F)) - E / F;
+ float whitetn = ((white * (A * white + C * B) + D * E) / (white * (A * white + B) + D * F)) - E / F;
+ return coltn / whitetn;
}
vec3 tonemap_aces(vec3 color) {
@@ -167,12 +152,12 @@ vec3 tonemap_aces(vec3 color) {
float c = 2.43f;
float d = 0.59f;
float e = 0.14f;
- return color = clamp((color*(a*color+b))/(color*(c*color+d)+e),vec3(0.0),vec3(1.0));
+ return color = clamp((color * (a * color + b)) / (color * (c * color + d) + e), vec3(0.0), vec3(1.0));
}
-vec3 tonemap_reindhart(vec3 color,float white) {
+vec3 tonemap_reindhart(vec3 color, float white) {
- return ( color * ( 1.0 + ( color / ( white) ) ) ) / ( 1.0 + color );
+ return (color * (1.0 + (color / (white)))) / (1.0 + color);
}
void main() {
@@ -181,10 +166,10 @@ void main() {
#ifdef USE_AUTO_EXPOSURE
- color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey;
+ color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / auto_exposure_grey;
#endif
- color*=exposure;
+ color *= exposure;
#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
#define USING_GLOW
@@ -195,56 +180,54 @@ void main() {
#ifdef USE_GLOW_LEVEL1
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,1).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 1).rgb;
#endif
#ifdef USE_GLOW_LEVEL2
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,2).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 2).rgb;
#endif
#ifdef USE_GLOW_LEVEL3
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,3).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 3).rgb;
#endif
#ifdef USE_GLOW_LEVEL4
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,4).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 4).rgb;
#endif
#ifdef USE_GLOW_LEVEL5
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,5).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 5).rgb;
#endif
#ifdef USE_GLOW_LEVEL6
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,6).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 6).rgb;
#endif
#ifdef USE_GLOW_LEVEL7
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,7).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(source_glow, uv_interp, 7).rgb;
#endif
-
glow *= glow_intensity;
#endif
-
#ifdef USE_REINDHART_TONEMAPPER
- color.rgb = tonemap_reindhart(color.rgb,white);
+ color.rgb = tonemap_reindhart(color.rgb, white);
-# if defined(USING_GLOW)
- glow = tonemap_reindhart(glow,white);
-# endif
+#if defined(USING_GLOW)
+ glow = tonemap_reindhart(glow, white);
+#endif
#endif
#ifdef USE_FILMIC_TONEMAPPER
- color.rgb = tonemap_filmic(color.rgb,white);
+ color.rgb = tonemap_filmic(color.rgb, white);
-# if defined(USING_GLOW)
- glow = tonemap_filmic(glow,white);
-# endif
+#if defined(USING_GLOW)
+ glow = tonemap_filmic(glow, white);
+#endif
#endif
@@ -252,26 +235,26 @@ void main() {
color.rgb = tonemap_aces(color.rgb);
-# if defined(USING_GLOW)
+#if defined(USING_GLOW)
glow = tonemap_aces(glow);
-# endif
+#endif
#endif
//regular Linear -> SRGB conversion
vec3 a = vec3(0.055);
- color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308)));
+ color.rgb = mix((vec3(1.0) + a) * pow(color.rgb, vec3(1.0 / 2.4)) - a, 12.92 * color.rgb, lessThan(color.rgb, vec3(0.0031308)));
#if defined(USING_GLOW)
- glow = mix( (vec3(1.0)+a)*pow(glow,vec3(1.0/2.4))-a , 12.92*glow , lessThan(glow,vec3(0.0031308)));
+ glow = mix((vec3(1.0) + a) * pow(glow, vec3(1.0 / 2.4)) - a, 12.92 * glow, lessThan(glow, vec3(0.0031308)));
#endif
-//glow needs to be added in SRGB space (together with image space effects)
+ //glow needs to be added in SRGB space (together with image space effects)
- color.rgb = clamp(color.rgb,0.0,1.0);
+ color.rgb = clamp(color.rgb, 0.0, 1.0);
#if defined(USING_GLOW)
- glow = clamp(glow,0.0,1.0);
+ glow = clamp(glow, 0.0, 1.0);
#endif
#ifdef USE_GLOW_REPLACE
@@ -291,33 +274,32 @@ void main() {
{
glow = (glow * 0.5) + 0.5;
- color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r)));
- color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g)));
- color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b)));
+ color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r)));
+ color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g)));
+ color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b)));
}
#endif
#if defined(USING_GLOW) && !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE)
//additive
- color.rgb+=glow;
+ color.rgb += glow;
#endif
#ifdef USE_BCS
- color.rgb = mix(vec3(0.0),color.rgb,bcs.x);
- color.rgb = mix(vec3(0.5),color.rgb,bcs.y);
- color.rgb = mix(vec3(dot(vec3(1.0),color.rgb)*0.33333),color.rgb,bcs.z);
+ color.rgb = mix(vec3(0.0), color.rgb, bcs.x);
+ color.rgb = mix(vec3(0.5), color.rgb, bcs.y);
+ color.rgb = mix(vec3(dot(vec3(1.0), color.rgb) * 0.33333), color.rgb, bcs.z);
#endif
#ifdef USE_COLOR_CORRECTION
- color.r = texture(color_correction,vec2(color.r,0.0)).r;
- color.g = texture(color_correction,vec2(color.g,0.0)).g;
- color.b = texture(color_correction,vec2(color.b,0.0)).b;
+ color.r = texture(color_correction, vec2(color.r, 0.0)).r;
+ color.g = texture(color_correction, vec2(color.g, 0.0)).g;
+ color.b = texture(color_correction, vec2(color.b, 0.0)).b;
#endif
-
- frag_color=vec4(color.rgb,1.0);
+ frag_color = vec4(color.rgb, 1.0);
}
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index bb4c8ab4d7..da87a71679 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -211,6 +211,10 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasGLES3::_bind_canvas_texture(con
} else {
+ 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)
@@ -248,6 +252,10 @@ RasterizerStorageGLES3::Texture *RasterizerCanvasGLES3::_bind_canvas_texture(con
} else {
+ 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);
@@ -824,6 +832,120 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
}
}
} break;
+ case Item::Command::TYPE_MULTIMESH: {
+
+ Item::CommandMultiMesh *mmesh = static_cast<Item::CommandMultiMesh *>(c);
+
+ RasterizerStorageGLES3::MultiMesh *multi_mesh = storage->multimesh_owner.getornull(mmesh->multimesh);
+
+ if (!multi_mesh)
+ break;
+
+ RasterizerStorageGLES3::Mesh *mesh_data = storage->mesh_owner.getornull(multi_mesh->mesh);
+
+ if (!mesh_data)
+ break;
+
+ RasterizerStorageGLES3::Texture *texture = _bind_canvas_texture(mmesh->texture, mmesh->normal_map);
+
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, multi_mesh->custom_data_format != VS::MULTIMESH_CUSTOM_DATA_NONE);
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, true);
+ //reset shader and force rebind
+ state.using_texture_rect = true;
+ _set_texture_rect_mode(false);
+
+ if (texture) {
+ Size2 texpixel_size(1.0 / texture->width, 1.0 / texture->height);
+ state.canvas_shader.set_uniform(CanvasShaderGLES3::COLOR_TEXPIXEL_SIZE, texpixel_size);
+ }
+
+ int amount = MAX(multi_mesh->size, multi_mesh->visible_instances);
+
+ for (int j = 0; j < mesh_data->surfaces.size(); j++) {
+ RasterizerStorageGLES3::Surface *s = mesh_data->surfaces[j];
+ // materials are ignored in 2D meshes, could be added but many things (ie, lighting mode, reading from screen, etc) would break as they are not meant be set up at this point of drawing
+ glBindVertexArray(s->instancing_array_id);
+
+ glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer
+
+ int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4;
+ glEnableVertexAttribArray(8);
+ glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0);
+ glVertexAttribDivisor(8, 1);
+ glEnableVertexAttribArray(9);
+ glVertexAttribPointer(9, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 4 * 4);
+ glVertexAttribDivisor(9, 1);
+
+ int color_ofs;
+
+ if (multi_mesh->transform_format == VS::MULTIMESH_TRANSFORM_3D) {
+ glEnableVertexAttribArray(10);
+ glVertexAttribPointer(10, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 8 * 4);
+ glVertexAttribDivisor(10, 1);
+ color_ofs = 12 * 4;
+ } else {
+ glDisableVertexAttribArray(10);
+ glVertexAttrib4f(10, 0, 0, 1, 0);
+ color_ofs = 8 * 4;
+ }
+
+ int custom_data_ofs = color_ofs;
+
+ switch (multi_mesh->color_format) {
+
+ case VS::MULTIMESH_COLOR_NONE: {
+ glDisableVertexAttribArray(11);
+ glVertexAttrib4f(11, 1, 1, 1, 1);
+ } break;
+ case VS::MULTIMESH_COLOR_8BIT: {
+ glEnableVertexAttribArray(11);
+ glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, ((uint8_t *)NULL) + color_ofs);
+ glVertexAttribDivisor(11, 1);
+ custom_data_ofs += 4;
+
+ } break;
+ case VS::MULTIMESH_COLOR_FLOAT: {
+ glEnableVertexAttribArray(11);
+ glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + color_ofs);
+ glVertexAttribDivisor(11, 1);
+ custom_data_ofs += 4 * 4;
+ } break;
+ }
+
+ switch (multi_mesh->custom_data_format) {
+
+ case VS::MULTIMESH_CUSTOM_DATA_NONE: {
+ glDisableVertexAttribArray(12);
+ glVertexAttrib4f(12, 1, 1, 1, 1);
+ } break;
+ case VS::MULTIMESH_CUSTOM_DATA_8BIT: {
+ glEnableVertexAttribArray(12);
+ glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, ((uint8_t *)NULL) + custom_data_ofs);
+ glVertexAttribDivisor(12, 1);
+
+ } break;
+ case VS::MULTIMESH_CUSTOM_DATA_FLOAT: {
+ glEnableVertexAttribArray(12);
+ glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + custom_data_ofs);
+ glVertexAttribDivisor(12, 1);
+ } break;
+ }
+
+ if (s->index_array_len) {
+ glDrawElementsInstanced(gl_primitive[s->primitive], s->index_array_len, (s->array_len >= (1 << 16)) ? GL_UNSIGNED_INT : GL_UNSIGNED_SHORT, 0, amount);
+ } else {
+ glDrawArraysInstanced(gl_primitive[s->primitive], 0, s->array_len, amount);
+ }
+
+ glBindVertexArray(0);
+ }
+
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCE_CUSTOM, false);
+ state.canvas_shader.set_conditional(CanvasShaderGLES3::USE_INSTANCING, false);
+ state.using_texture_rect = true;
+ _set_texture_rect_mode(false);
+
+ } break;
case Item::Command::TYPE_PARTICLES: {
Item::CommandParticles *particles_cmd = static_cast<Item::CommandParticles *>(c);
@@ -832,6 +954,9 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
if (!particles)
break;
+ if (particles->inactive && !particles->emitting)
+ break;
+
glVertexAttrib4f(VS::ARRAY_COLOR, 1, 1, 1, 1); //not used, so keep white
VisualServerRaster::redraw_request();
@@ -997,13 +1122,11 @@ void RasterizerCanvasGLES3::_canvas_item_render_commands(Item *p_item, Item *cur
glEnable(GL_SCISSOR_TEST);
//glScissor(viewport.x+current_clip->final_clip_rect.pos.x,viewport.y+ (viewport.height-(current_clip->final_clip_rect.pos.y+current_clip->final_clip_rect.size.height)),
//current_clip->final_clip_rect.size.width,current_clip->final_clip_rect.size.height);
-
- int x = current_clip->final_clip_rect.position.x;
int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y);
- int w = current_clip->final_clip_rect.size.x;
- int h = current_clip->final_clip_rect.size.y;
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP])
+ y = current_clip->final_clip_rect.position.y;
- glScissor(x, y, w, h);
+ glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y);
reclip = false;
}
@@ -1138,7 +1261,11 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons
if (current_clip) {
glEnable(GL_SCISSOR_TEST);
- glScissor(current_clip->final_clip_rect.position.x, (rt_size.height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.height)), current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height);
+ int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y);
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP])
+ y = current_clip->final_clip_rect.position.y;
+
+ glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.x, current_clip->final_clip_rect.size.y);
} else {
@@ -1160,8 +1287,8 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons
{
//skeleton handling
- if (ci->skeleton.is_valid()) {
- skeleton = storage->skeleton_owner.getornull(ci->skeleton);
+ if (ci->skeleton.is_valid() && storage->skeleton_owner.owns(ci->skeleton)) {
+ skeleton = storage->skeleton_owner.get(ci->skeleton);
if (!skeleton->use_2d) {
skeleton = NULL;
} else {
@@ -1261,6 +1388,10 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons
continue;
}
+ 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) {
@@ -1515,7 +1646,10 @@ void RasterizerCanvasGLES3::canvas_render_items(Item *p_item_list, int p_z, cons
if (reclip) {
glEnable(GL_SCISSOR_TEST);
- glScissor(current_clip->final_clip_rect.position.x, (rt_size.height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.height)), current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height);
+ int y = storage->frame.current_rt->height - (current_clip->final_clip_rect.position.y + current_clip->final_clip_rect.size.y);
+ if (storage->frame.current_rt->flags[RasterizerStorage::RENDER_TARGET_VFLIP])
+ y = current_clip->final_clip_rect.position.y;
+ glScissor(current_clip->final_clip_rect.position.x, y, current_clip->final_clip_rect.size.width, current_clip->final_clip_rect.size.height);
}
p_item_list = p_item_list->next;
@@ -1537,17 +1671,12 @@ void RasterizerCanvasGLES3::canvas_debug_viewport_shadows(Light *p_lights_with_s
int ofs = h;
glDisable(GL_BLEND);
- //print_line(" debug lights ");
while (light) {
-
- //print_line("debug light");
if (light->shadow_buffer.is_valid()) {
- //print_line("sb is valid");
RasterizerStorageGLES3::CanvasLightShadow *sb = storage->canvas_light_shadow_owner.get(light->shadow_buffer);
if (sb) {
glBindTexture(GL_TEXTURE_2D, sb->distance);
- //glBindTexture(GL_TEXTURE_2D,storage->resources.white_tex);
draw_generic_textured_rect(Rect2(h, ofs, w - h * 2, h), Rect2(0, 0, 1, 1));
ofs += h * 2;
}
@@ -1657,19 +1786,7 @@ void RasterizerCanvasGLES3::canvas_light_shadow_buffer_update(RID p_buffer, cons
} break;
}
}
- /*
- if (i==0) {
- for(int i=0;i<cc->lines.size();i++) {
- Vector2 p = instance->xform_cache.xform(cc->lines.get(i));
- Plane pp(Vector3(p.x,p.y,0),1);
- pp.normal = light.xform(pp.normal);
- pp = projection.xform4(pp);
- print_line(itos(i)+": "+pp.normal/pp.d);
- //pp=light_mat.xform4(pp);
- //print_line(itos(i)+": "+pp.normal/pp.d);
- }
- }
-*/
+
glBindVertexArray(cc->array_id);
glDrawElements(GL_TRIANGLES, cc->len * 3, GL_UNSIGNED_SHORT, 0);
@@ -1875,7 +1992,7 @@ void RasterizerCanvasGLES3::initialize() {
}
{
- uint32_t poly_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
+ uint32_t poly_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_buffer_size_kb", 128);
poly_size *= 1024; //kb
poly_size = MAX(poly_size, (2 + 2 + 4) * 4 * sizeof(float));
glGenBuffers(1, &data.polygon_buffer);
@@ -1922,7 +2039,7 @@ void RasterizerCanvasGLES3::initialize() {
glGenVertexArrays(1, &data.polygon_buffer_pointer_array);
- uint32_t index_size = GLOBAL_DEF("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128);
+ uint32_t index_size = GLOBAL_DEF_RST("rendering/limits/buffers/canvas_polygon_index_buffer_size_kb", 128);
index_size *= 1024; //kb
glGenBuffers(1, &data.polygon_index_buffer);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, data.polygon_index_buffer);
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 1abdaa5f80..e4824695d5 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -33,7 +33,9 @@
#include "gl_context/context_gl.h"
#include "os/os.h"
#include "project_settings.h"
+
#include <string.h>
+
RasterizerStorage *RasterizerGLES3::get_storage() {
return storage;
@@ -134,30 +136,32 @@ typedef void (*DEBUGPROCARB)(GLenum source,
typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam);
-void RasterizerGLES3::initialize() {
-
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("Using GLES3 video driver");
- }
+Error RasterizerGLES3::is_viable() {
#ifdef GLAD_ENABLED
if (!gladLoadGL()) {
ERR_PRINT("Error initializing GLAD");
+ return ERR_UNAVAILABLE;
}
// GLVersion seems to be used for both GL and GL ES, so we need different version checks for them
#ifdef OPENGL_ENABLED // OpenGL 3.3 Core Profile required
- if (GLVersion.major < 3 && GLVersion.minor < 3) {
+ if (GLVersion.major < 3 || (GLVersion.major == 3 && GLVersion.minor < 3)) {
#else // OpenGL ES 3.0
if (GLVersion.major < 3) {
#endif
- ERR_PRINT("Your system's graphic drivers seem not to support OpenGL 3.3 / OpenGL ES 3.0, sorry :(\n"
- "Try a drivers update, buy a new GPU or try software rendering on Linux; Godot will now crash with a segmentation fault.");
- OS::get_singleton()->alert("Your system's graphic drivers seem not to support OpenGL 3.3 / OpenGL ES 3.0, sorry :(\n"
- "Godot Engine will self-destruct as soon as you acknowledge this error message.",
- "Fatal error: Insufficient OpenGL / GLES driver support");
+ return ERR_UNAVAILABLE;
}
+#endif // GLAD_ENABLED
+ return OK;
+}
+
+void RasterizerGLES3::initialize() {
+
+ print_verbose("Using GLES3 video driver");
+
+#ifdef GLAD_ENABLED
if (OS::get_singleton()->is_stdout_verbose()) {
if (GLAD_GL_ARB_debug_output) {
glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
@@ -167,7 +171,6 @@ void RasterizerGLES3::initialize() {
print_line("OpenGL debugging not supported!");
}
}
-
#endif // GLAD_ENABLED
/* // For debugging
@@ -192,22 +195,15 @@ void RasterizerGLES3::initialize() {
scene->initialize();
}
-void RasterizerGLES3::begin_frame() {
-
- uint64_t tick = OS::get_singleton()->get_ticks_usec();
+void RasterizerGLES3::begin_frame(double frame_step) {
- double delta = double(tick - prev_ticks) / 1000000.0;
- delta *= Engine::get_singleton()->get_time_scale();
+ time_total += frame_step;
- time_total += delta;
-
- if (delta == 0) {
+ if (frame_step == 0) {
//to avoid hiccups
- delta = 0.001;
+ frame_step = 0.001;
}
- prev_ticks = tick;
-
double time_roll_over = GLOBAL_GET("rendering/limits/time/time_rollover_secs");
if (time_total > time_roll_over)
time_total = 0; //roll over every day (should be customz
@@ -217,9 +213,7 @@ void RasterizerGLES3::begin_frame() {
storage->frame.time[2] = Math::fmod(time_total, 900);
storage->frame.time[3] = Math::fmod(time_total, 60);
storage->frame.count++;
- storage->frame.delta = delta;
-
- storage->frame.prev_tick = tick;
+ storage->frame.delta = frame_step;
storage->update_dirty_resources();
@@ -234,7 +228,7 @@ void RasterizerGLES3::set_current_render_target(RID p_render_target) {
if (!p_render_target.is_valid() && storage->frame.current_rt && storage->frame.clear_request) {
//handle pending clear request, if the framebuffer was not cleared
glBindFramebuffer(GL_FRAMEBUFFER, storage->frame.current_rt->fbo);
- print_line("unbind clear of: " + storage->frame.clear_request_color);
+
glClearColor(
storage->frame.clear_request_color.r,
storage->frame.clear_request_color.g,
@@ -281,7 +275,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
if (p_image.is_null() || p_image->empty())
return;
- begin_frame();
+ begin_frame(0.0);
int window_w = OS::get_singleton()->get_video_mode(0).width;
int window_h = OS::get_singleton()->get_video_mode(0).height;
@@ -299,7 +293,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
canvas->canvas_begin();
RID texture = storage->texture_create();
- storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), p_image->get_format(), VS::TEXTURE_FLAG_FILTER);
+ storage->texture_allocate(texture, p_image->get_width(), p_image->get_height(), 0, p_image->get_format(), VS::TEXTURE_TYPE_2D, VS::TEXTURE_FLAG_FILTER);
storage->texture_set_data(texture, p_image);
Rect2 imgrect(0, 0, p_image->get_width(), p_image->get_height());
@@ -333,28 +327,7 @@ void RasterizerGLES3::set_boot_image(const Ref<Image> &p_image, const Color &p_c
storage->free(texture); // free since it's only one frame that stays there
- if (OS::get_singleton()->is_layered_allowed()) {
- if (OS::get_singleton()->get_window_per_pixel_transparency_enabled()) {
-#if (defined WINDOWS_ENABLED) && !(defined UWP_ENABLED)
- Size2 wndsize = OS::get_singleton()->get_layered_buffer_size();
- uint8_t *data = OS::get_singleton()->get_layered_buffer_data();
- if (data) {
- glReadPixels(0, 0, wndsize.x, wndsize.y, GL_BGRA, GL_UNSIGNED_BYTE, data);
- OS::get_singleton()->swap_layered_buffer();
-
- return;
- }
-#endif
- } else {
- //clear alpha
- glColorMask(false, false, false, true);
- glClearColor(0, 0, 0, 1);
- glClear(GL_COLOR_BUFFER_BIT);
- glColorMask(true, true, true, true);
- }
- }
-
- OS::get_singleton()->swap_buffers();
+ end_frame(true);
}
void RasterizerGLES3::blit_render_target_to_screen(RID p_render_target, const Rect2 &p_screen_rect, int p_screen) {
@@ -451,7 +424,6 @@ RasterizerGLES3::RasterizerGLES3() {
scene->storage = storage;
storage->scene = scene;
- prev_ticks = 0;
time_total = 0;
}
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index 5213101778..0a264caf8f 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -44,7 +44,6 @@ class RasterizerGLES3 : public Rasterizer {
RasterizerCanvasGLES3 *canvas;
RasterizerSceneGLES3 *scene;
- uint64_t prev_ticks;
double time_total;
public:
@@ -55,7 +54,7 @@ public:
virtual void set_boot_image(const Ref<Image> &p_image, const Color &p_color, bool p_scale);
virtual void initialize();
- virtual void begin_frame();
+ virtual void begin_frame(double frame_step);
virtual void set_current_render_target(RID p_render_target);
virtual void restore_render_target();
virtual void clear_render_target(const Color &p_color);
@@ -63,9 +62,10 @@ public:
virtual void end_frame(bool p_swap_buffers);
virtual void finalize();
+ static Error is_viable();
static void make_current();
-
static void register_config();
+
RasterizerGLES3();
~RasterizerGLES3();
};
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 03ff84c093..88f14890ef 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -355,7 +355,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in
bool should_redraw = shadow_atlas->quadrants[q].shadows[s].version != p_light_version;
if (!should_realloc) {
- shadow_atlas->quadrants[q].shadows[s].version = p_light_version;
+ shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
//already existing, see if it should redraw or it's just OK
return should_redraw;
}
@@ -365,7 +365,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in
//find a better place
if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, shadow_atlas->quadrants[q].subdivision, tick, new_quadrant, new_shadow)) {
//found a better place!
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows[new_shadow];
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
if (sh->owner.is_valid()) {
//is taken, but is invalid, erasing it
shadow_atlas->shadow_owners.erase(sh->owner);
@@ -374,8 +374,8 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in
}
//erase previous
- shadow_atlas->quadrants[q].shadows[s].version = 0;
- shadow_atlas->quadrants[q].shadows[s].owner = RID();
+ shadow_atlas->quadrants[q].shadows.write[s].version = 0;
+ shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
sh->owner = p_light_intance;
sh->alloc_tick = tick;
@@ -395,7 +395,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in
//already existing, see if it should redraw or it's just OK
- shadow_atlas->quadrants[q].shadows[s].version = p_light_version;
+ shadow_atlas->quadrants[q].shadows.write[s].version = p_light_version;
return should_redraw;
}
@@ -405,7 +405,7 @@ bool RasterizerSceneGLES3::shadow_atlas_update_light(RID p_atlas, RID p_light_in
//find a better place
if (_shadow_atlas_find_shadow(shadow_atlas, valid_quadrants, valid_quadrant_count, -1, tick, new_quadrant, new_shadow)) {
//found a better place!
- ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows[new_shadow];
+ ShadowAtlas::Quadrant::Shadow *sh = &shadow_atlas->quadrants[new_quadrant].shadows.write[new_shadow];
if (sh->owner.is_valid()) {
//is taken, but is invalid, erasing it
shadow_atlas->shadow_owners.erase(sh->owner);
@@ -502,7 +502,7 @@ void RasterizerSceneGLES3::reflection_atlas_set_size(RID p_ref_atlas, int p_size
//erase probes reference to this
if (reflection_atlas->reflections[i].owner.is_valid()) {
ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner);
- reflection_atlas->reflections[i].owner = RID();
+ reflection_atlas->reflections.write[i].owner = RID();
ERR_CONTINUE(!reflection_probe_instance);
reflection_probe_instance->reflection_atlas_index = -1;
@@ -574,7 +574,7 @@ void RasterizerSceneGLES3::reflection_atlas_set_subdivision(RID p_ref_atlas, int
//erase probes reference to this
if (reflection_atlas->reflections[i].owner.is_valid()) {
ReflectionProbeInstance *reflection_probe_instance = reflection_probe_instance_owner.getornull(reflection_atlas->reflections[i].owner);
- reflection_atlas->reflections[i].owner = RID();
+ reflection_atlas->reflections.write[i].owner = RID();
ERR_CONTINUE(!reflection_probe_instance);
reflection_probe_instance->reflection_atlas_index = -1;
@@ -629,7 +629,7 @@ void RasterizerSceneGLES3::reflection_probe_release_atlas_index(RID p_instance)
ERR_FAIL_COND(reflection_atlas->reflections[rpi->reflection_atlas_index].owner != rpi->self);
- reflection_atlas->reflections[rpi->reflection_atlas_index].owner = RID();
+ reflection_atlas->reflections.write[rpi->reflection_atlas_index].owner = RID();
rpi->reflection_atlas_index = -1;
rpi->atlas = RID();
@@ -701,8 +701,8 @@ bool RasterizerSceneGLES3::reflection_probe_instance_begin_render(RID p_instance
victim_rpi->reflection_atlas_index = -1;
}
- reflection_atlas->reflections[best_free].owner = p_instance;
- reflection_atlas->reflections[best_free].last_frame = storage->frame.count;
+ reflection_atlas->reflections.write[best_free].owner = p_instance;
+ reflection_atlas->reflections.write[best_free].last_frame = storage->frame.count;
rpi->reflection_atlas_index = best_free;
rpi->atlas = p_reflection_atlas;
@@ -896,7 +896,7 @@ void RasterizerSceneGLES3::environment_set_ssr(RID p_env, bool p_enable, int p_m
env->ssr_roughness = p_roughness;
}
-void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
+void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VisualServer::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness) {
Environment *env = environment_owner.getornull(p_env);
ERR_FAIL_COND(!env);
@@ -908,6 +908,7 @@ void RasterizerSceneGLES3::environment_set_ssao(RID p_env, bool p_enable, float
env->ssao_intensity2 = p_intensity2;
env->ssao_bias = p_bias;
env->ssao_light_affect = p_light_affect;
+ env->ssao_ao_channel_affect = p_ao_channel_affect;
env->ssao_color = p_color;
env->ssao_filter = p_blur;
env->ssao_quality = p_quality;
@@ -1007,7 +1008,10 @@ RID RasterizerSceneGLES3::light_instance_create(RID p_light) {
light_instance->light = p_light;
light_instance->light_ptr = storage->light_owner.getornull(p_light);
- ERR_FAIL_COND_V(!light_instance->light_ptr, RID());
+ if (!light_instance->light_ptr) {
+ memdelete(light_instance);
+ ERR_FAIL_COND_V(!light_instance->light_ptr, RID());
+ }
light_instance->self = light_instance_owner.make_rid(light_instance);
@@ -1189,6 +1193,7 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m
int tc = p_material->textures.size();
RID *textures = p_material->textures.ptrw();
ShaderLanguage::ShaderNode::Uniform::Hint *texture_hints = p_material->shader->texture_hints.ptrw();
+ const ShaderLanguage::DataType *texture_types = p_material->shader->texture_types.ptr();
state.current_main_tex = 0;
@@ -1197,33 +1202,16 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m
glActiveTexture(GL_TEXTURE0 + i);
GLenum target;
- GLuint tex;
-
- RasterizerStorageGLES3::Texture *t = storage->texture_owner.getornull(textures[i]);
+ GLuint tex = 0;
- if (!t) {
- //check hints
- target = GL_TEXTURE_2D;
+ RasterizerStorageGLES3::Texture *t = storage->texture_owner.getptr(textures[i]);
- switch (texture_hints[i]) {
- case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO:
- case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: {
- tex = storage->resources.black_tex;
- } break;
- case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
- tex = storage->resources.aniso_tex;
- } break;
- case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: {
- tex = storage->resources.normal_tex;
+ if (t) {
- } break;
- default: {
- tex = storage->resources.white_tex;
- } break;
+ if (t->redraw_if_visible) { //must check before proxy because this is often used with proxies
+ VisualServerRaster::redraw_request();
}
- } else {
-
t = t->get_ptr(); //resolve for proxies
#ifdef TOOLS_ENABLED
if (t->detect_3d) {
@@ -1241,6 +1229,59 @@ bool RasterizerSceneGLES3::_setup_material(RasterizerStorageGLES3::Material *p_m
target = t->target;
tex = t->tex_id;
+ } else {
+
+ switch (texture_types[i]) {
+ case ShaderLanguage::TYPE_ISAMPLER2D:
+ case ShaderLanguage::TYPE_USAMPLER2D:
+ case ShaderLanguage::TYPE_SAMPLER2D: {
+ target = GL_TEXTURE_2D;
+
+ switch (texture_hints[i]) {
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK_ALBEDO:
+ case ShaderLanguage::ShaderNode::Uniform::HINT_BLACK: {
+ tex = storage->resources.black_tex;
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_ANISO: {
+ tex = storage->resources.aniso_tex;
+ } break;
+ case ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL: {
+ tex = storage->resources.normal_tex;
+
+ } break;
+ default: {
+ tex = storage->resources.white_tex;
+ } break;
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_SAMPLERCUBE: {
+ // TODO
+ } break;
+
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER3D:
+ case ShaderLanguage::TYPE_SAMPLER3D: {
+
+ target = GL_TEXTURE_3D;
+
+ switch (texture_hints[i]) {
+
+ // TODO
+ default: {
+ tex = storage->resources.white_tex_3d;
+ } break;
+ }
+
+ } break;
+
+ case ShaderLanguage::TYPE_ISAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_USAMPLER2DARRAY:
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY: {
+ // TODO
+ } break;
+ }
}
glBindTexture(target, tex);
@@ -1335,7 +1376,7 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo
glBindBuffer(GL_ARRAY_BUFFER, multi_mesh->buffer); //modify the buffer
- int stride = (multi_mesh->xform_floats + multi_mesh->color_floats) * 4;
+ int stride = (multi_mesh->xform_floats + multi_mesh->color_floats + multi_mesh->custom_data_floats) * 4;
glEnableVertexAttribArray(8);
glVertexAttribPointer(8, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + 0);
glVertexAttribDivisor(8, 1);
@@ -1356,6 +1397,8 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo
color_ofs = 8 * 4;
}
+ int custom_data_ofs = color_ofs;
+
switch (multi_mesh->color_format) {
case VS::MULTIMESH_COLOR_NONE: {
@@ -1366,12 +1409,33 @@ void RasterizerSceneGLES3::_setup_geometry(RenderList::Element *e, const Transfo
glEnableVertexAttribArray(11);
glVertexAttribPointer(11, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, ((uint8_t *)NULL) + color_ofs);
glVertexAttribDivisor(11, 1);
+ custom_data_ofs += 4;
} break;
case VS::MULTIMESH_COLOR_FLOAT: {
glEnableVertexAttribArray(11);
glVertexAttribPointer(11, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + color_ofs);
glVertexAttribDivisor(11, 1);
+ custom_data_ofs += 4 * 4;
+ } break;
+ }
+
+ switch (multi_mesh->custom_data_format) {
+
+ case VS::MULTIMESH_CUSTOM_DATA_NONE: {
+ glDisableVertexAttribArray(12);
+ glVertexAttrib4f(12, 1, 1, 1, 1);
+ } break;
+ case VS::MULTIMESH_CUSTOM_DATA_8BIT: {
+ glEnableVertexAttribArray(12);
+ glVertexAttribPointer(12, 4, GL_UNSIGNED_BYTE, GL_TRUE, stride, ((uint8_t *)NULL) + custom_data_ofs);
+ glVertexAttribDivisor(12, 1);
+
+ } break;
+ case VS::MULTIMESH_CUSTOM_DATA_FLOAT: {
+ glEnableVertexAttribArray(12);
+ glVertexAttribPointer(12, 4, GL_FLOAT, GL_FALSE, stride, ((uint8_t *)NULL) + custom_data_ofs);
+ glVertexAttribDivisor(12, 1);
} break;
}
@@ -1545,6 +1609,11 @@ void RasterizerSceneGLES3::_render_geometry(RenderList::Element *e) {
RasterizerStorageGLES3::Texture *t = storage->texture_owner.get(c.texture);
t = t->get_ptr(); //resolve for proxies
+
+ if (t->redraw_if_visible) {
+ VisualServerRaster::redraw_request();
+ }
+
#ifdef TOOLS_ENABLED
if (t->detect_3d) {
t->detect_3d(t->detect_3d_ud);
@@ -2507,6 +2576,7 @@ void RasterizerSceneGLES3::_setup_environment(Environment *env, const CameraMatr
state.env_radiance_data.ambient_contribution = env->ambient_sky_contribution;
state.ubo_data.ambient_occlusion_affect_light = env->ssao_light_affect;
+ state.ubo_data.ambient_occlusion_affect_ssao = env->ssao_ao_channel_affect;
//fog
@@ -3813,8 +3883,8 @@ void RasterizerSceneGLES3::_post_process(Environment *env, const CameraMatrix &p
state.exposure_shader.set_conditional(ExposureShaderGLES3::EXPOSURE_END, false);
//last step, swap with the framebuffer exposure, so the right exposure is kept int he framebuffer
- SWAP(exposure_shrink[exposure_shrink.size() - 1].fbo, storage->frame.current_rt->exposure.fbo);
- SWAP(exposure_shrink[exposure_shrink.size() - 1].color, storage->frame.current_rt->exposure.color);
+ SWAP(exposure_shrink.write[exposure_shrink.size() - 1].fbo, storage->frame.current_rt->exposure.fbo);
+ SWAP(exposure_shrink.write[exposure_shrink.size() - 1].color, storage->frame.current_rt->exposure.color);
glViewport(0, 0, storage->frame.current_rt->width, storage->frame.current_rt->height);
@@ -4051,6 +4121,7 @@ void RasterizerSceneGLES3::render_scene(const Transform &p_cam_transform, const
state.ubo_data.z_slope_scale = 0;
state.ubo_data.shadow_dual_paraboloid_render_side = 0;
state.ubo_data.shadow_dual_paraboloid_render_zfar = 0;
+ state.ubo_data.opaque_prepass_threshold = 0.99;
p_cam_projection.get_viewport_size(state.ubo_data.viewport_size[0], state.ubo_data.viewport_size[1]);
@@ -4663,6 +4734,7 @@ void RasterizerSceneGLES3::render_shadow(RID p_light, RID p_shadow_atlas, int p_
state.ubo_data.z_slope_scale = normal_bias;
state.ubo_data.shadow_dual_paraboloid_render_side = dp_direction;
state.ubo_data.shadow_dual_paraboloid_render_zfar = zfar;
+ state.ubo_data.opaque_prepass_threshold = 0.1;
_setup_environment(NULL, light_projection, light_transform);
@@ -4741,7 +4813,7 @@ bool RasterizerSceneGLES3::free(RID p_rid) {
uint32_t q = (key >> ShadowAtlas::QUADRANT_SHIFT) & 0x3;
uint32_t s = key & ShadowAtlas::SHADOW_INDEX_MASK;
- shadow_atlas->quadrants[q].shadows[s].owner = RID();
+ shadow_atlas->quadrants[q].shadows.write[s].owner = RID();
shadow_atlas->shadow_owners.erase(p_rid);
}
@@ -4831,7 +4903,7 @@ void RasterizerSceneGLES3::initialize() {
glBufferData(GL_UNIFORM_BUFFER, sizeof(State::EnvironmentRadianceUBO), &state.env_radiance_ubo, GL_DYNAMIC_DRAW);
glBindBuffer(GL_UNIFORM_BUFFER, 0);
- render_list.max_elements = GLOBAL_DEF("rendering/limits/rendering/max_renderable_elements", (int)RenderList::DEFAULT_MAX_ELEMENTS);
+ 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)
diff --git a/drivers/gles3/rasterizer_scene_gles3.h b/drivers/gles3/rasterizer_scene_gles3.h
index a6faeef473..cf387a69bc 100644
--- a/drivers/gles3/rasterizer_scene_gles3.h
+++ b/drivers/gles3/rasterizer_scene_gles3.h
@@ -140,6 +140,8 @@ public:
float reflection_multiplier;
float subsurface_scatter_width;
float ambient_occlusion_affect_light;
+ float ambient_occlusion_affect_ssao;
+ float opaque_prepass_threshold;
uint32_t fog_depth_enabled;
float fog_depth_begin;
@@ -151,6 +153,7 @@ public:
float fog_height_max;
float fog_height_curve;
// make sure this struct is padded to be a multiple of 16 bytes for webgl
+ float pad[2];
} ubo_data;
@@ -385,6 +388,7 @@ public:
float ssao_radius2;
float ssao_bias;
float ssao_light_affect;
+ float ssao_ao_channel_affect;
Color ssao_color;
VS::EnvironmentSSAOQuality ssao_quality;
float ssao_bilateral_sharpness;
@@ -465,6 +469,7 @@ public:
ssao_radius2 = 0.0;
ssao_bias = 0.01;
ssao_light_affect = 0;
+ ssao_ao_channel_affect = 0;
ssao_filter = VS::ENV_SSAO_BLUR_3x3;
ssao_quality = VS::ENV_SSAO_QUALITY_LOW;
ssao_bilateral_sharpness = 4;
@@ -543,7 +548,7 @@ public:
virtual void environment_set_fog(RID p_env, bool p_enable, float p_begin, float p_end, RID p_gradient_texture);
virtual void environment_set_ssr(RID p_env, bool p_enable, int p_max_steps, float p_fade_in, float p_fade_out, float p_depth_tolerance, bool p_roughness);
- virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
+ virtual void environment_set_ssao(RID p_env, bool p_enable, float p_radius, float p_intensity, float p_radius2, float p_intensity2, float p_bias, float p_light_affect, float p_ao_channel_affect, const Color &p_color, VS::EnvironmentSSAOQuality p_quality, VS::EnvironmentSSAOBlur p_blur, float p_bilateral_sharpness);
virtual void environment_set_tonemap(RID p_env, VS::EnvironmentToneMapper p_tone_mapper, float p_exposure, float p_white, bool p_auto_exposure, float p_min_luminance, float p_max_luminance, float p_auto_exp_speed, float p_auto_exp_scale);
diff --git a/drivers/gles3/rasterizer_storage_gles3.cpp b/drivers/gles3/rasterizer_storage_gles3.cpp
index 66a8a931e2..83f731f610 100644
--- a/drivers/gles3/rasterizer_storage_gles3.cpp
+++ b/drivers/gles3/rasterizer_storage_gles3.cpp
@@ -118,10 +118,11 @@ void glTexStorage2DCustom(GLenum target, GLsizei levels, GLenum internalformat,
GLuint RasterizerStorageGLES3::system_fbo = 0;
-Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb) {
+Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb) const {
r_compressed = false;
r_gl_format = 0;
+ r_real_format = p_format;
Ref<Image> image = p_image;
srgb = false;
@@ -565,6 +566,7 @@ Ref<Image> RasterizerStorageGLES3::_get_gl_image_and_format(const Ref<Image> &p_
r_gl_internal_format = (config.srgb_decode_supported || (p_flags & VS::TEXTURE_FLAG_CONVERT_TO_LINEAR)) ? GL_SRGB8_ALPHA8 : GL_RGBA8;
r_gl_type = GL_UNSIGNED_BYTE;
r_compressed = false;
+ r_real_format = Image::FORMAT_RGBA8;
srgb = true;
return image;
@@ -595,7 +597,7 @@ RID RasterizerStorageGLES3::texture_create() {
return texture_owner.make_rid(texture);
}
-void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags) {
+void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VisualServer::TextureType p_type, uint32_t p_flags) {
GLenum format;
GLenum internal_format;
@@ -612,15 +614,38 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
ERR_FAIL_COND(!texture);
texture->width = p_width;
texture->height = p_height;
+ texture->depth = p_depth_3d;
texture->format = p_format;
texture->flags = p_flags;
texture->stored_cube_sides = 0;
- texture->target = (p_flags & VS::TEXTURE_FLAG_CUBEMAP) ? GL_TEXTURE_CUBE_MAP : GL_TEXTURE_2D;
- _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, format, internal_format, type, compressed, srgb);
+ texture->type = p_type;
+
+ switch (p_type) {
+ case VS::TEXTURE_TYPE_2D: {
+ texture->target = GL_TEXTURE_2D;
+ texture->images.resize(1);
+ } break;
+ case VS::TEXTURE_TYPE_CUBEMAP: {
+ texture->target = GL_TEXTURE_CUBE_MAP;
+ texture->images.resize(6);
+ } break;
+ case VS::TEXTURE_TYPE_2D_ARRAY: {
+ texture->target = GL_TEXTURE_2D_ARRAY;
+ texture->images.resize(p_depth_3d);
+ } break;
+ case VS::TEXTURE_TYPE_3D: {
+ texture->target = GL_TEXTURE_3D;
+ texture->images.resize(p_depth_3d);
+ } break;
+ }
+
+ Image::Format real_format;
+ _get_gl_image_and_format(Ref<Image>(), texture->format, texture->flags, real_format, format, internal_format, type, compressed, srgb);
texture->alloc_width = texture->width;
texture->alloc_height = texture->height;
+ texture->alloc_depth = texture->depth;
texture->gl_format_cache = format;
texture->gl_type_cache = type;
@@ -633,7 +658,34 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ if (p_type == VS::TEXTURE_TYPE_3D || p_type == VS::TEXTURE_TYPE_2D_ARRAY) {
+
+ int width = p_width;
+ int height = p_height;
+ int depth = p_depth_3d;
+
+ int mipmaps = 0;
+
+ while (width != 1 && height != 1) {
+ glTexImage3D(texture->target, 0, internal_format, width, height, depth, 0, format, type, NULL);
+
+ width = MAX(1, width / 2);
+ height = MAX(1, height / 2);
+
+ if (p_type == VS::TEXTURE_TYPE_3D) {
+ depth = MAX(1, depth / 2);
+ }
+
+ mipmaps++;
+
+ if (!(p_flags & VS::TEXTURE_FLAG_MIPMAPS))
+ break;
+ }
+
+ glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
+
+ } else if (p_flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
//prealloc if video
glTexImage2D(texture->target, 0, internal_format, p_width, p_height, 0, format, type, NULL);
}
@@ -641,7 +693,7 @@ void RasterizerStorageGLES3::texture_allocate(RID p_texture, int p_width, int p_
texture->active = true;
}
-void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side) {
+void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer) {
Texture *texture = texture_owner.get(p_texture);
@@ -658,10 +710,11 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
bool srgb;
if (config.keep_original_textures && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
- texture->images[p_cube_side] = p_image;
+ texture->images.write[p_layer] = p_image;
}
- Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, format, internal_format, type, compressed, srgb);
+ Image::Format real_format;
+ Ref<Image> img = _get_gl_image_and_format(p_image, p_image->get_format(), texture->flags, real_format, format, internal_format, type, compressed, srgb);
if (config.shrink_textures_x2 && (p_image->has_mipmaps() || !p_image->is_compressed()) && !(texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING)) {
@@ -677,7 +730,23 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
}
};
- GLenum blit_target = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D;
+ GLenum blit_target;
+
+ switch (texture->type) {
+ case VS::TEXTURE_TYPE_2D: {
+ blit_target = GL_TEXTURE_2D;
+ } break;
+ case VS::TEXTURE_TYPE_CUBEMAP: {
+ ERR_FAIL_INDEX(p_layer, 6);
+ blit_target = _cube_side_enum[p_layer];
+ } break;
+ case VS::TEXTURE_TYPE_2D_ARRAY: {
+ blit_target = GL_TEXTURE_2D_ARRAY;
+ } break;
+ case VS::TEXTURE_TYPE_3D: {
+ blit_target = GL_TEXTURE_3D;
+ } break;
+ }
texture->data_size = img->get_data().size();
PoolVector<uint8_t>::Read read = img->get_data().read();
@@ -785,20 +854,36 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
//print_line("mipmap: "+itos(i)+" size: "+itos(size)+" w: "+itos(mm_w)+", h: "+itos(mm_h));
- if (texture->compressed) {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) {
+
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- int bw = w;
- int bh = h;
+ int bw = w;
+ int bh = h;
- glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
+ glCompressedTexImage2D(blit_target, i, internal_format, bw, bh, 0, size, &read[ofs]);
+ } else {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
+ glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]);
+ } else {
+ glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ }
+ }
} else {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- if (texture->flags & VS::TEXTURE_FLAG_USED_FOR_STREAMING) {
- glTexSubImage2D(blit_target, i, 0, 0, w, h, format, type, &read[ofs]);
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+
+ int bw = w;
+ int bh = h;
+
+ glCompressedTexSubImage3D(blit_target, i, 0, 0, p_layer, bw, bh, 1, internal_format, size, &read[ofs]);
} else {
- glTexImage2D(blit_target, i, internal_format, w, h, 0, format, type, &read[ofs]);
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+
+ glTexSubImage3D(blit_target, i, 0, 0, p_layer, w, h, 1, format, type, &read[ofs]);
}
}
tsize += size;
@@ -813,14 +898,17 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
//printf("texture: %i x %i - size: %i - total: %i\n",texture->width,texture->height,tsize,_rinfo.texture_mem);
- texture->stored_cube_sides |= (1 << p_cube_side);
+ texture->stored_cube_sides |= (1 << p_layer);
- if ((texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP) || texture->stored_cube_sides == (1 << 6) - 1)) {
+ if ((texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) && (texture->flags & VS::TEXTURE_FLAG_MIPMAPS) && mipmaps == 1 && !texture->ignore_mipmaps && (texture->type != VS::TEXTURE_TYPE_CUBEMAP || texture->stored_cube_sides == (1 << 6) - 1)) {
//generate mipmaps if they were requested and the image does not contain them
glGenerateMipmap(texture->target);
} else if (mipmaps > 1) {
glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0);
glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, mipmaps - 1);
+ } else {
+ glTexParameteri(texture->target, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(texture->target, GL_TEXTURE_MAX_LEVEL, 0);
}
texture->mipmaps = mipmaps;
@@ -831,7 +919,7 @@ void RasterizerStorageGLES3::texture_set_data(RID p_texture, const Ref<Image> &p
// Uploads pixel data to a sub-region of a texture, for the specified mipmap.
// The texture pixels must have been allocated before, because most features seen in texture_set_data() make no sense in a partial update.
// TODO If we want this to be usable without pre-filling pixels with a full image, we have to call glTexImage2D() with null data.
-void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side) {
+void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer) {
Texture *texture = texture_owner.get(p_texture);
@@ -857,9 +945,26 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I
p_sub_img = p_image->get_rect(Rect2(src_x, src_y, src_w, src_h));
}
- Ref<Image> img = _get_gl_image_and_format(p_sub_img, p_sub_img->get_format(), texture->flags, format, internal_format, type, compressed, srgb);
+ 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 = (texture->target == GL_TEXTURE_CUBE_MAP) ? _cube_side_enum[p_cube_side] : GL_TEXTURE_2D;
+ switch (texture->type) {
+ case VS::TEXTURE_TYPE_2D: {
+ blit_target = GL_TEXTURE_2D;
+ } break;
+ case VS::TEXTURE_TYPE_CUBEMAP: {
+ ERR_FAIL_INDEX(p_layer, 6);
+ blit_target = _cube_side_enum[p_layer];
+ } break;
+ case VS::TEXTURE_TYPE_2D_ARRAY: {
+ blit_target = GL_TEXTURE_2D_ARRAY;
+ } break;
+ case VS::TEXTURE_TYPE_3D: {
+ blit_target = GL_TEXTURE_3D;
+ } break;
+ }
PoolVector<uint8_t>::Read read = img->get_data().read();
@@ -869,18 +974,38 @@ void RasterizerStorageGLES3::texture_set_data_partial(RID p_texture, const Ref<I
int src_data_size = img->get_data().size();
int src_ofs = 0;
- if (texture->compressed) {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
- glCompressedTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, internal_format, src_data_size, &read[src_ofs]);
+ if (texture->type == VS::TEXTURE_TYPE_2D || texture->type == VS::TEXTURE_TYPE_CUBEMAP) {
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glCompressedTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, internal_format, src_data_size, &read[src_ofs]);
+ } else {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ // `format` has to match the internal_format used when the texture was created
+ glTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, format, type, &read[src_ofs]);
+ }
} else {
- glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
- // `format` has to match the internal_format used when the texture was created
- glTexSubImage2D(blit_target, p_dst_mip, dst_x, dst_y, src_w, src_h, format, type, &read[src_ofs]);
+ if (texture->compressed) {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
+ glCompressedTexSubImage3D(blit_target, p_dst_mip, dst_x, dst_y, p_layer, src_w, src_h, 1, format, src_data_size, &read[src_ofs]);
+ } else {
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ // `format` has to match the internal_format used when the texture was created
+ glTexSubImage3D(blit_target, p_dst_mip, dst_x, dst_y, p_layer, src_w, src_h, 1, format, type, &read[src_ofs]);
+ }
+ }
+
+ if (texture->flags & VS::TEXTURE_FLAG_FILTER) {
+
+ glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_LINEAR); // Linear Filtering
+
+ } else {
+
+ glTexParameteri(texture->target, GL_TEXTURE_MAG_FILTER, GL_NEAREST); // raw Filtering
}
}
-Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side) const {
+Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, int p_layer) const {
Texture *texture = texture_owner.get(p_texture);
@@ -888,15 +1013,23 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSi
ERR_FAIL_COND_V(!texture->active, Ref<Image>());
ERR_FAIL_COND_V(texture->data_size == 0 && !texture->render_target, Ref<Image>());
- if (!texture->images[p_cube_side].is_null()) {
- return texture->images[p_cube_side];
+ if (texture->type == VS::TEXTURE_TYPE_CUBEMAP && p_layer < 6 && !texture->images[p_layer].is_null()) {
+ return texture->images[p_layer];
}
#ifdef GLES_OVER_GL
+ 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, texture->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 ? -1 : 0);
data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
PoolVector<uint8_t>::Write wb = data.write();
@@ -913,7 +1046,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSi
int ofs = 0;
if (i > 0) {
- ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->format, i - 1);
+ ofs = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, real_format, i - 1);
}
if (texture->compressed) {
@@ -949,7 +1082,7 @@ Ref<Image> RasterizerStorageGLES3::texture_get_data(RID p_texture, VS::CubeMapSi
(a | a << 2 | a << 4 | a << 6) << 24;
}
} else {
- img_format = texture->format;
+ img_format = real_format;
}
wb = PoolVector<uint8_t>::Write();
@@ -977,10 +1110,10 @@ void RasterizerStorageGLES3::texture_set_flags(RID p_texture, uint32_t p_flags)
bool had_mipmaps = texture->flags & VS::TEXTURE_FLAG_MIPMAPS;
+ texture->flags = p_flags;
+
glActiveTexture(GL_TEXTURE0);
glBindTexture(texture->target, texture->tex_id);
- uint32_t cube = texture->flags & VS::TEXTURE_FLAG_CUBEMAP;
- texture->flags = p_flags | cube; // can't remove a cube from being a cube
if (((texture->flags & VS::TEXTURE_FLAG_REPEAT) || (texture->flags & VS::TEXTURE_FLAG_MIRRORED_REPEAT)) && texture->target != GL_TEXTURE_CUBE_MAP) {
@@ -1058,6 +1191,14 @@ Image::Format RasterizerStorageGLES3::texture_get_format(RID p_texture) const {
return texture->format;
}
+
+VisualServer::TextureType RasterizerStorageGLES3::texture_get_type(RID p_texture) const {
+ Texture *texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture, VS::TEXTURE_TYPE_2D);
+
+ return texture->type;
+}
uint32_t RasterizerStorageGLES3::texture_get_texid(RID p_texture) const {
Texture *texture = texture_owner.get(p_texture);
@@ -1083,7 +1224,16 @@ uint32_t RasterizerStorageGLES3::texture_get_height(RID p_texture) const {
return texture->height;
}
-void RasterizerStorageGLES3::texture_set_size_override(RID p_texture, int p_width, int p_height) {
+uint32_t RasterizerStorageGLES3::texture_get_depth(RID p_texture) const {
+
+ Texture *texture = texture_owner.get(p_texture);
+
+ ERR_FAIL_COND_V(!texture, 0);
+
+ return texture->depth;
+}
+
+void RasterizerStorageGLES3::texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth) {
Texture *texture = texture_owner.get(p_texture);
@@ -1123,8 +1273,9 @@ void RasterizerStorageGLES3::texture_debug_usage(List<VS::TextureInfo> *r_info)
VS::TextureInfo tinfo;
tinfo.path = t->path;
tinfo.format = t->format;
- tinfo.size.x = t->alloc_width;
- tinfo.size.y = t->alloc_height;
+ tinfo.width = t->alloc_width;
+ tinfo.height = t->alloc_height;
+ tinfo.depth = 0;
tinfo.bytes = t->total_data_size;
r_info->push_back(tinfo);
}
@@ -1169,7 +1320,7 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_
Texture *texture = texture_owner.get(p_source);
ERR_FAIL_COND_V(!texture, RID());
- ERR_FAIL_COND_V(!(texture->flags & VS::TEXTURE_FLAG_CUBEMAP), RID());
+ ERR_FAIL_COND_V(texture->type != VS::TEXTURE_TYPE_CUBEMAP, RID());
bool use_float = config.hdr_supported;
@@ -1285,7 +1436,8 @@ RID RasterizerStorageGLES3::texture_create_radiance_cubemap(RID p_source, int p_
Texture *ctex = memnew(Texture);
- ctex->flags = VS::TEXTURE_FLAG_CUBEMAP | VS::TEXTURE_FLAG_MIPMAPS | VS::TEXTURE_FLAG_FILTER;
+ ctex->type = VS::TEXTURE_TYPE_CUBEMAP;
+ ctex->flags = VS::TEXTURE_FLAG_MIPMAPS | VS::TEXTURE_FLAG_FILTER;
ctex->width = p_resolution;
ctex->height = p_resolution;
ctex->alloc_width = p_resolution;
@@ -1328,6 +1480,13 @@ void RasterizerStorageGLES3::texture_set_proxy(RID p_texture, RID p_proxy) {
}
}
+void RasterizerStorageGLES3::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {
+
+ Texture *texture = texture_owner.get(p_texture);
+ ERR_FAIL_COND(!texture);
+ texture->redraw_if_visible = p_enable;
+}
+
RID RasterizerStorageGLES3::sky_create() {
Sky *sky = memnew(Sky);
@@ -1758,6 +1917,7 @@ void RasterizerStorageGLES3::_update_shader(Shader *p_shader) const {
p_shader->ubo_offsets = gen_code.uniform_offsets;
p_shader->texture_count = gen_code.texture_uniforms.size();
p_shader->texture_hints = gen_code.texture_hints;
+ p_shader->texture_types = gen_code.texture_types;
p_shader->uses_vertex_time = gen_code.uses_vertex_time;
p_shader->uses_fragment_time = gen_code.uses_fragment_time;
@@ -1868,6 +2028,13 @@ 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_SAMPLER3D:
+ case ShaderLanguage::TYPE_ISAMPLER3D:
+ case ShaderLanguage::TYPE_USAMPLER3D: {
+ pi.type = Variant::OBJECT;
+ pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
+ pi.hint_string = "Texture3D";
+ } break;
case ShaderLanguage::TYPE_SAMPLERCUBE: {
pi.type = Variant::OBJECT;
@@ -2642,6 +2809,7 @@ void RasterizerStorageGLES3::_update_material(Material *material) {
//set up the texture array, for easy access when it needs to be drawn
if (material->shader && material->shader->texture_count) {
+ material->texture_is_3d.resize(material->shader->texture_count);
material->textures.resize(material->shader->texture_count);
for (Map<StringName, ShaderLanguage::ShaderNode::Uniform>::Element *E = material->shader->uniforms.front(); E; E = E->next()) {
@@ -2651,6 +2819,16 @@ void RasterizerStorageGLES3::_update_material(Material *material) {
RID texture;
+ switch (E->get().type) {
+ case ShaderLanguage::TYPE_SAMPLER3D:
+ case ShaderLanguage::TYPE_SAMPLER2DARRAY: {
+ material->texture_is_3d.write[E->get().texture_order] = true;
+ } break;
+ default: {
+ material->texture_is_3d.write[E->get().texture_order] = false;
+ } break;
+ }
+
Map<StringName, Variant>::Element *V = material->params.find(E->key());
if (V) {
texture = V->get();
@@ -2663,11 +2841,12 @@ void RasterizerStorageGLES3::_update_material(Material *material) {
}
}
- material->textures[E->get().texture_order] = texture;
+ material->textures.write[E->get().texture_order] = texture;
}
} else {
material->textures.clear();
+ material->texture_is_3d.clear();
}
}
@@ -2968,9 +3147,9 @@ void RasterizerStorageGLES3::mesh_add_surface(RID p_mesh, uint32_t p_format, VS:
for (int i = 0; i < surface->skeleton_bone_used.size(); i++) {
if (surface->skeleton_bone_aabb[i].size.x < 0 || surface->skeleton_bone_aabb[i].size.y < 0 || surface->skeleton_bone_aabb[i].size.z < 0) {
- surface->skeleton_bone_used[i] = false;
+ surface->skeleton_bone_used.write[i] = false;
} else {
- surface->skeleton_bone_used[i] = true;
+ surface->skeleton_bone_used.write[i] = true;
}
}
@@ -3233,7 +3412,7 @@ void RasterizerStorageGLES3::mesh_surface_update_region(RID p_mesh, int p_surfac
PoolVector<uint8_t>::Read r = p_data.read();
- glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->array_id);
+ glBindBuffer(GL_ARRAY_BUFFER, mesh->surfaces[p_surface]->vertex_id);
glBufferSubData(GL_ARRAY_BUFFER, p_offset, total_size, r.ptr());
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
@@ -3397,6 +3576,7 @@ Vector<PoolVector<uint8_t> > RasterizerStorageGLES3::mesh_surface_get_blend_shap
return bsarr;
}
+
Vector<AABB> RasterizerStorageGLES3::mesh_surface_get_skeleton_aabb(RID p_mesh, int p_surface) const {
const Mesh *mesh = mesh_owner.getornull(p_mesh);
@@ -3448,6 +3628,7 @@ void RasterizerStorageGLES3::mesh_remove_surface(RID p_mesh, int p_surface) {
mesh->instance_change_notify();
}
+
int RasterizerStorageGLES3::mesh_get_surface_count(RID p_mesh) const {
const Mesh *mesh = mesh_owner.getornull(p_mesh);
@@ -3461,6 +3642,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();
}
AABB RasterizerStorageGLES3::mesh_get_custom_aabb(RID p_mesh) const {
@@ -3816,12 +3998,12 @@ RID RasterizerStorageGLES3::multimesh_create() {
return multimesh_owner.make_rid(multimesh);
}
-void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format) {
+void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data_format) {
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
ERR_FAIL_COND(!multimesh);
- if (multimesh->size == p_instances && multimesh->transform_format == p_transform_format && multimesh->color_format == p_color_format)
+ if (multimesh->size == p_instances && multimesh->transform_format == p_transform_format && multimesh->color_format == p_color_format && multimesh->custom_data_format == p_data_format)
return;
if (multimesh->buffer) {
@@ -3832,6 +4014,7 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances
multimesh->size = p_instances;
multimesh->transform_format = p_transform_format;
multimesh->color_format = p_color_format;
+ multimesh->custom_data_format = p_data_format;
if (multimesh->size) {
@@ -3849,36 +4032,49 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances
multimesh->color_floats = 4;
}
- int format_floats = multimesh->color_floats + multimesh->xform_floats;
+ if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE) {
+ multimesh->custom_data_floats = 0;
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ multimesh->custom_data_floats = 1;
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ multimesh->custom_data_floats = 4;
+ }
+
+ int format_floats = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+
multimesh->data.resize(format_floats * p_instances);
- for (int i = 0; i < p_instances; i += format_floats) {
+
+ 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[i + 0] = 1.0;
- multimesh->data[i + 1] = 0.0;
- multimesh->data[i + 2] = 0.0;
- multimesh->data[i + 3] = 0.0;
- multimesh->data[i + 4] = 0.0;
- multimesh->data[i + 5] = 1.0;
- multimesh->data[i + 6] = 0.0;
- multimesh->data[i + 7] = 0.0;
+ 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;
color_from = 8;
+ custom_data_from = 8;
} else {
- multimesh->data[i + 0] = 1.0;
- multimesh->data[i + 1] = 0.0;
- multimesh->data[i + 2] = 0.0;
- multimesh->data[i + 3] = 0.0;
- multimesh->data[i + 4] = 0.0;
- multimesh->data[i + 5] = 1.0;
- multimesh->data[i + 6] = 0.0;
- multimesh->data[i + 7] = 0.0;
- multimesh->data[i + 8] = 0.0;
- multimesh->data[i + 9] = 0.0;
- multimesh->data[i + 10] = 1.0;
- multimesh->data[i + 11] = 0.0;
+ 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;
color_from = 12;
+ custom_data_from = 12;
}
if (multimesh->color_format == VS::MULTIMESH_COLOR_NONE) {
@@ -3891,13 +4087,34 @@ void RasterizerStorageGLES3::multimesh_allocate(RID p_multimesh, int p_instances
} cu;
cu.colu = 0xFFFFFFFF;
- multimesh->data[i + color_from + 0] = cu.colf;
+ multimesh->data.write[i + color_from + 0] = cu.colf;
+ custom_data_from = color_from + 1;
} else if (multimesh->color_format == VS::MULTIMESH_COLOR_FLOAT) {
- multimesh->data[i + color_from + 0] = 1.0;
- multimesh->data[i + color_from + 1] = 1.0;
- multimesh->data[i + color_from + 2] = 1.0;
- multimesh->data[i + color_from + 3] = 1.0;
+ 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;
+ custom_data_from = color_from + 4;
+ }
+
+ if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE) {
+ //none
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ cu.colu = 0;
+ multimesh->data.write[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;
}
}
@@ -3958,8 +4175,8 @@ void RasterizerStorageGLES3::multimesh_instance_set_transform(RID p_multimesh, i
ERR_FAIL_INDEX(p_index, multimesh->size);
ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D);
- int stride = multimesh->color_floats + multimesh->xform_floats;
- float *dataptr = &multimesh->data[stride * p_index];
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index];
dataptr[0] = p_transform.basis.elements[0][0];
dataptr[1] = p_transform.basis.elements[0][1];
@@ -3989,8 +4206,8 @@ void RasterizerStorageGLES3::multimesh_instance_set_transform_2d(RID p_multimesh
ERR_FAIL_INDEX(p_index, multimesh->size);
ERR_FAIL_COND(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D);
- int stride = multimesh->color_floats + multimesh->xform_floats;
- float *dataptr = &multimesh->data[stride * p_index];
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index];
dataptr[0] = p_transform.elements[0][0];
dataptr[1] = p_transform.elements[1][0];
@@ -4015,8 +4232,8 @@ void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh, int p
ERR_FAIL_INDEX(p_index, multimesh->size);
ERR_FAIL_COND(multimesh->color_format == VS::MULTIMESH_COLOR_NONE);
- int stride = multimesh->color_floats + multimesh->xform_floats;
- float *dataptr = &multimesh->data[stride * p_index + multimesh->xform_floats];
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats];
if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
@@ -4041,6 +4258,38 @@ void RasterizerStorageGLES3::multimesh_instance_set_color(RID p_multimesh, int p
}
}
+void RasterizerStorageGLES3::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_custom_data) {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_INDEX(p_index, multimesh->size);
+ ERR_FAIL_COND(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE);
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats];
+
+ if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+
+ uint8_t *data8 = (uint8_t *)dataptr;
+ data8[0] = CLAMP(p_custom_data.r * 255.0, 0, 255);
+ data8[1] = CLAMP(p_custom_data.g * 255.0, 0, 255);
+ data8[2] = CLAMP(p_custom_data.b * 255.0, 0, 255);
+ data8[3] = CLAMP(p_custom_data.a * 255.0, 0, 255);
+
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ dataptr[0] = p_custom_data.r;
+ dataptr[1] = p_custom_data.g;
+ dataptr[2] = p_custom_data.b;
+ dataptr[3] = p_custom_data.a;
+ }
+
+ multimesh->dirty_data = true;
+ multimesh->dirty_aabb = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
+}
RID RasterizerStorageGLES3::multimesh_get_mesh(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
@@ -4056,8 +4305,8 @@ Transform RasterizerStorageGLES3::multimesh_instance_get_transform(RID p_multime
ERR_FAIL_INDEX_V(p_index, multimesh->size, Transform());
ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_2D, Transform());
- int stride = multimesh->color_floats + multimesh->xform_floats;
- float *dataptr = &multimesh->data[stride * p_index];
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index];
Transform xform;
@@ -4083,8 +4332,8 @@ Transform2D RasterizerStorageGLES3::multimesh_instance_get_transform_2d(RID p_mu
ERR_FAIL_INDEX_V(p_index, multimesh->size, Transform2D());
ERR_FAIL_COND_V(multimesh->transform_format == VS::MULTIMESH_TRANSFORM_3D, Transform2D());
- int stride = multimesh->color_floats + multimesh->xform_floats;
- float *dataptr = &multimesh->data[stride * p_index];
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index];
Transform2D xform;
@@ -4105,8 +4354,8 @@ Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int
ERR_FAIL_INDEX_V(p_index, multimesh->size, Color());
ERR_FAIL_COND_V(multimesh->color_format == VS::MULTIMESH_COLOR_NONE, Color());
- int stride = multimesh->color_floats + multimesh->xform_floats;
- float *dataptr = &multimesh->data[stride * p_index + multimesh->xform_floats];
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats];
if (multimesh->color_format == VS::MULTIMESH_COLOR_8BIT) {
union {
@@ -4131,6 +4380,59 @@ Color RasterizerStorageGLES3::multimesh_instance_get_color(RID p_multimesh, int
return Color();
}
+Color RasterizerStorageGLES3::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_INDEX_V(p_index, multimesh->size, Color());
+ ERR_FAIL_COND_V(multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_NONE, Color());
+
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
+ float *dataptr = &multimesh->data.write[stride * p_index + multimesh->xform_floats + multimesh->color_floats];
+
+ if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_8BIT) {
+ union {
+ uint32_t colu;
+ float colf;
+ } cu;
+
+ cu.colf = dataptr[0];
+
+ return Color::hex(BSWAP32(cu.colu));
+
+ } else if (multimesh->custom_data_format == VS::MULTIMESH_CUSTOM_DATA_FLOAT) {
+ Color c;
+ c.r = dataptr[0];
+ c.g = dataptr[1];
+ c.b = dataptr[2];
+ c.a = dataptr[3];
+
+ return c;
+ }
+
+ return Color();
+}
+
+void RasterizerStorageGLES3::multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array) {
+
+ MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
+ ERR_FAIL_COND(!multimesh);
+
+ int dsize = multimesh->data.size();
+
+ ERR_FAIL_COND(dsize != p_array.size());
+
+ PoolVector<float>::Read r = p_array.read();
+ copymem(multimesh->data.ptrw(), r.ptr(), dsize * sizeof(float));
+
+ multimesh->dirty_data = true;
+ multimesh->dirty_aabb = true;
+
+ if (!multimesh->update_list.in_list()) {
+ multimesh_update_list.add(&multimesh->update_list);
+ }
+}
+
void RasterizerStorageGLES3::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
MultiMesh *multimesh = multimesh_owner.getornull(p_multimesh);
@@ -4179,7 +4481,7 @@ void RasterizerStorageGLES3::update_dirty_multimeshes() {
mesh_aabb.size += Vector3(0.001, 0.001, 0.001);
}
- int stride = multimesh->color_floats + multimesh->xform_floats;
+ int stride = multimesh->color_floats + multimesh->xform_floats + multimesh->custom_data_floats;
int count = multimesh->data.size();
float *data = multimesh->data.ptrw();
@@ -5642,7 +5944,7 @@ void RasterizerStorageGLES3::particles_set_draw_pass_mesh(RID p_particles, int p
Particles *particles = particles_owner.getornull(p_particles);
ERR_FAIL_COND(!particles);
ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
- particles->draw_passes[p_pass] = p_mesh;
+ particles->draw_passes.write[p_pass] = p_mesh;
}
void RasterizerStorageGLES3::particles_restart(RID p_particles) {
@@ -6516,7 +6818,7 @@ void RasterizerStorageGLES3::_render_target_allocate(RenderTarget *rt) {
for (int j = 0; j < rt->effects.mip_maps[i].sizes.size(); j++) {
- RenderTarget::Effects::MipMaps::Size &mm = rt->effects.mip_maps[i].sizes[j];
+ RenderTarget::Effects::MipMaps::Size &mm = rt->effects.mip_maps[i].sizes.write[j];
glGenFramebuffers(1, &mm.fbo);
glBindFramebuffer(GL_FRAMEBUFFER, mm.fbo);
@@ -6696,7 +6998,10 @@ RID RasterizerStorageGLES3::canvas_light_shadow_buffer_create(int p_width) {
//printf("errnum: %x\n",status);
glBindFramebuffer(GL_FRAMEBUFFER, RasterizerStorageGLES3::system_fbo);
- ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID());
+ if (status != GL_FRAMEBUFFER_COMPLETE) {
+ memdelete(cls);
+ ERR_FAIL_COND_V(status != GL_FRAMEBUFFER_COMPLETE, RID());
+ }
return canvas_light_shadow_owner.make_rid(cls);
}
@@ -6869,6 +7174,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
info.texture_mem -= texture->total_data_size;
texture_owner.free(p_rid);
memdelete(texture);
+
} else if (sky_owner.owns(p_rid)) {
// delete the sky
Sky *sky = sky_owner.get(p_rid);
@@ -6928,7 +7234,7 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
for (int i = 0; i < ins->materials.size(); i++) {
if (ins->materials[i] == p_rid) {
- ins->materials[i] = RID();
+ ins->materials.write[i] = RID();
}
}
}
@@ -7078,6 +7384,9 @@ bool RasterizerStorageGLES3::free(RID p_rid) {
bool RasterizerStorageGLES3::has_os_feature(const String &p_feature) const {
+ if (p_feature == "bptc")
+ return config.bptc_supported;
+
if (p_feature == "s3tc")
return config.s3tc_supported;
@@ -7278,6 +7587,15 @@ void RasterizerStorageGLES3::initialize() {
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 8, 8, 0, GL_RGB, GL_UNSIGNED_BYTE, anisotexdata);
glGenerateMipmap(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, 0);
+
+ glGenTextures(1, &resources.white_tex_3d);
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_3D, resources.white_tex_3d);
+ glTexImage3D(GL_TEXTURE_3D, 0, GL_RGB, 2, 2, 2, 0, GL_RGB, GL_UNSIGNED_BYTE, whitetexdata);
+
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_BASE_LEVEL, 0);
+ glTexParameteri(GL_TEXTURE_3D, GL_TEXTURE_MAX_LEVEL, 0);
}
glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &config.max_texture_image_units);
@@ -7336,7 +7654,7 @@ void RasterizerStorageGLES3::initialize() {
{
//transform feedback buffers
- uint32_t xf_feedback_size = GLOBAL_DEF("rendering/limits/buffers/blend_shape_max_buffer_size_kb", 4096);
+ uint32_t xf_feedback_size = GLOBAL_DEF_RST("rendering/limits/buffers/blend_shape_max_buffer_size_kb", 4096);
for (int i = 0; i < 2; i++) {
glGenBuffers(1, &resources.transform_feedback_buffers[i]);
@@ -7359,7 +7677,6 @@ void RasterizerStorageGLES3::initialize() {
#endif
frame.count = 0;
- frame.prev_tick = 0;
frame.delta = 0;
frame.current_rt = NULL;
config.keep_original_textures = false;
diff --git a/drivers/gles3/rasterizer_storage_gles3.h b/drivers/gles3/rasterizer_storage_gles3.h
index 6b626cbd00..b74dd77e26 100644
--- a/drivers/gles3/rasterizer_storage_gles3.h
+++ b/drivers/gles3/rasterizer_storage_gles3.h
@@ -123,6 +123,8 @@ public:
GLuint normal_tex;
GLuint aniso_tex;
+ GLuint white_tex_3d;
+
GLuint quadie;
GLuint quadie_array;
@@ -248,9 +250,10 @@ public:
String path;
uint32_t flags;
- int width, height;
- int alloc_width, alloc_height;
+ int width, height, depth;
+ int alloc_width, alloc_height, alloc_depth;
Image::Format format;
+ VS::TextureType type;
GLenum target;
GLenum gl_format_cache;
@@ -268,12 +271,13 @@ public:
GLuint tex_id;
bool using_srgb;
+ bool redraw_if_visible;
uint16_t stored_cube_sides;
RenderTarget *render_target;
- Ref<Image> images[6];
+ Vector<Ref<Image> > images;
VisualServer::TextureDetectCallback detect_3d;
void *detect_3d_ud;
@@ -306,6 +310,7 @@ public:
detect_normal = NULL;
detect_normal_ud = NULL;
proxy = NULL;
+ redraw_if_visible = false;
}
_ALWAYS_INLINE_ Texture *get_ptr() {
@@ -335,20 +340,22 @@ public:
mutable RID_Owner<Texture> texture_owner;
- Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb);
+ Ref<Image> _get_gl_image_and_format(const Ref<Image> &p_image, Image::Format p_format, uint32_t p_flags, Image::Format &r_real_format, GLenum &r_gl_format, GLenum &r_gl_internal_format, GLenum &r_gl_type, bool &r_compressed, bool &srgb) const;
virtual RID texture_create();
- virtual void texture_allocate(RID p_texture, int p_width, int p_height, Image::Format p_format, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
- virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
- virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT);
- virtual Ref<Image> texture_get_data(RID p_texture, VS::CubeMapSide p_cube_side = VS::CUBEMAP_LEFT) const;
+ virtual void texture_allocate(RID p_texture, int p_width, int p_height, int p_depth_3d, Image::Format p_format, VS::TextureType p_type, uint32_t p_flags = VS::TEXTURE_FLAGS_DEFAULT);
+ virtual void texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer = 0);
+ virtual void texture_set_data_partial(RID p_texture, const Ref<Image> &p_image, int src_x, int src_y, int src_w, int src_h, int dst_x, int dst_y, int p_dst_mip, int p_layer = 0);
+ virtual Ref<Image> texture_get_data(RID p_texture, int p_layer = 0) const;
virtual void texture_set_flags(RID p_texture, uint32_t p_flags);
virtual uint32_t texture_get_flags(RID p_texture) const;
virtual Image::Format texture_get_format(RID p_texture) const;
+ virtual VS::TextureType texture_get_type(RID p_texture) const;
virtual uint32_t texture_get_texid(RID p_texture) const;
virtual uint32_t texture_get_width(RID p_texture) const;
virtual uint32_t texture_get_height(RID p_texture) const;
- virtual void texture_set_size_override(RID p_texture, int p_width, int p_height);
+ virtual uint32_t texture_get_depth(RID p_texture) const;
+ virtual void texture_set_size_override(RID p_texture, int p_width, int p_height, int p_depth);
virtual void texture_set_path(RID p_texture, const String &p_path);
virtual String texture_get_path(RID p_texture) const;
@@ -366,6 +373,7 @@ public:
virtual void texture_set_detect_normal_callback(RID p_texture, VisualServer::TextureDetectCallback p_callback, void *p_userdata);
virtual void texture_set_proxy(RID p_texture, RID p_proxy);
+ virtual void texture_set_force_redraw_if_visible(RID p_texture, bool p_enable);
/* SKY API */
@@ -407,6 +415,7 @@ public:
Map<StringName, RID> default_textures;
+ Vector<ShaderLanguage::DataType> texture_types;
Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints;
bool valid;
@@ -529,6 +538,7 @@ public:
Map<StringName, Variant> params;
SelfList<Material> list;
SelfList<Material> dirty_list;
+ Vector<bool> texture_is_3d;
Vector<RID> textures;
float line_width;
int render_priority;
@@ -690,7 +700,6 @@ public:
AABB custom_aabb;
mutable uint64_t last_pass;
SelfList<MultiMesh>::List multimeshes;
-
_FORCE_INLINE_ void update_multimeshes() {
SelfList<MultiMesh> *mm = multimeshes.first();
@@ -756,6 +765,7 @@ public:
int size;
VS::MultimeshTransformFormat transform_format;
VS::MultimeshColorFormat color_format;
+ VS::MultimeshCustomDataFormat custom_data_format;
Vector<float> data;
AABB aabb;
SelfList<MultiMesh> update_list;
@@ -765,6 +775,7 @@ public:
int xform_floats;
int color_floats;
+ int custom_data_floats;
bool dirty_aabb;
bool dirty_data;
@@ -776,11 +787,13 @@ public:
dirty_data = true;
xform_floats = 0;
color_floats = 0;
+ custom_data_floats = 0;
visible_instances = -1;
size = 0;
buffer = 0;
transform_format = VS::MULTIMESH_TRANSFORM_2D;
color_format = VS::MULTIMESH_COLOR_NONE;
+ custom_data_format = VS::MULTIMESH_CUSTOM_DATA_NONE;
}
};
@@ -792,19 +805,23 @@ public:
virtual RID multimesh_create();
- virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format);
+ virtual void multimesh_allocate(RID p_multimesh, int p_instances, VS::MultimeshTransformFormat p_transform_format, VS::MultimeshColorFormat p_color_format, VS::MultimeshCustomDataFormat p_data_format = VS::MULTIMESH_CUSTOM_DATA_NONE);
virtual int multimesh_get_instance_count(RID p_multimesh) const;
virtual void multimesh_set_mesh(RID p_multimesh, RID p_mesh);
virtual void multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform &p_transform);
virtual void multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform);
virtual void multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color);
+ virtual void multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color);
virtual RID multimesh_get_mesh(RID p_multimesh) const;
virtual Transform multimesh_instance_get_transform(RID p_multimesh, int p_index) const;
virtual Transform2D multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const;
virtual Color multimesh_instance_get_color(RID p_multimesh, int p_index) const;
+ virtual Color multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const;
+
+ virtual void multimesh_set_as_bulk_array(RID p_multimesh, const PoolVector<float> &p_array);
virtual void multimesh_set_visible_instances(RID p_multimesh, int p_visible);
virtual int multimesh_get_visible_instances(RID p_multimesh) const;
@@ -1417,7 +1434,6 @@ public:
int canvas_draw_commands;
float time[4];
float delta;
- uint64_t prev_tick;
uint64_t count;
} frame;
diff --git a/drivers/gles3/shader_compiler_gles3.cpp b/drivers/gles3/shader_compiler_gles3.cpp
index eb8d6c485b..a78a392cbd 100644
--- a/drivers/gles3/shader_compiler_gles3.cpp
+++ b/drivers/gles3/shader_compiler_gles3.cpp
@@ -341,6 +341,7 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
r_gen_code.texture_uniforms.resize(max_texture_uniforms);
r_gen_code.texture_hints.resize(max_texture_uniforms);
+ r_gen_code.texture_types.resize(max_texture_uniforms);
Vector<int> uniform_sizes;
Vector<int> uniform_alignments;
@@ -365,17 +366,18 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
if (SL::is_sampler_type(E->get().type)) {
r_gen_code.vertex_global += ucode;
r_gen_code.fragment_global += ucode;
- r_gen_code.texture_uniforms[E->get().texture_order] = _mkid(E->key());
- r_gen_code.texture_hints[E->get().texture_order] = E->get().hint;
+ r_gen_code.texture_uniforms.write[E->get().texture_order] = _mkid(E->key());
+ r_gen_code.texture_hints.write[E->get().texture_order] = E->get().hint;
+ r_gen_code.texture_types.write[E->get().texture_order] = E->get().type;
} else {
if (!uses_uniforms) {
r_gen_code.defines.push_back(String("#define USE_MATERIAL\n").ascii());
uses_uniforms = true;
}
- uniform_defines[E->get().order] = ucode;
- uniform_sizes[E->get().order] = _get_datatype_size(E->get().type);
- uniform_alignments[E->get().order] = _get_datatype_alignment(E->get().type);
+ uniform_defines.write[E->get().order] = ucode;
+ uniform_sizes.write[E->get().order] = _get_datatype_size(E->get().type);
+ uniform_alignments.write[E->get().order] = _get_datatype_alignment(E->get().type);
}
p_actions.uniforms->insert(E->key(), E->get());
@@ -434,8 +436,6 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
continue;
}
- print_line("u - "+String(E->key())+" offset: "+itos(r_gen_code.uniform_offsets[E->get().order]));
-
}
*/
@@ -700,6 +700,11 @@ String ShaderCompilerGLES3::_dump_node_code(SL::Node *p_node, int p_level, Gener
}
} else if (cfnode->flow_op == SL::FLOW_OP_DISCARD) {
+ if (p_actions.usage_flag_pointers.has("DISCARD") && !used_flag_pointers.has("DISCARD")) {
+ *p_actions.usage_flag_pointers["DISCARD"] = true;
+ used_flag_pointers.insert("DISCARD");
+ }
+
code = "discard;";
} else if (cfnode->flow_op == SL::FLOW_OP_CONTINUE) {
@@ -780,8 +785,6 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL"] = "normal";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP"] = "normal_map";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMALMAP_DEPTH"] = "normal_depth";
- actions[VS::SHADER_CANVAS_ITEM].renames["UV"] = "uv_interp";
- actions[VS::SHADER_CANVAS_ITEM].renames["COLOR"] = "color";
actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE"] = "color_texture";
actions[VS::SHADER_CANVAS_ITEM].renames["TEXTURE_PIXEL_SIZE"] = "color_texpixel_size";
actions[VS::SHADER_CANVAS_ITEM].renames["NORMAL_TEXTURE"] = "normal_texture";
@@ -824,7 +827,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_SPATIAL].renames["UV2"] = "uv2_interp";
actions[VS::SHADER_SPATIAL].renames["COLOR"] = "color_interp";
actions[VS::SHADER_SPATIAL].renames["POINT_SIZE"] = "gl_PointSize";
- //actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"]=ShaderLanguage::TYPE_INT;
+ actions[VS::SHADER_SPATIAL].renames["INSTANCE_ID"] = "gl_InstanceID";
//builtins
@@ -846,13 +849,11 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_SPATIAL].renames["CLEARCOAT_GLOSS"] = "clearcoat_gloss";
actions[VS::SHADER_SPATIAL].renames["ANISOTROPY"] = "anisotropy";
actions[VS::SHADER_SPATIAL].renames["ANISOTROPY_FLOW"] = "anisotropy_flow";
- //actions[VS::SHADER_SPATIAL].renames["SSS_SPREAD"] = "sss_spread";
actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
actions[VS::SHADER_SPATIAL].renames["TRANSMISSION"] = "transmission";
actions[VS::SHADER_SPATIAL].renames["AO"] = "ao";
actions[VS::SHADER_SPATIAL].renames["AO_LIGHT_AFFECT"] = "ao_light_affect";
actions[VS::SHADER_SPATIAL].renames["EMISSION"] = "emission";
- //actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"]=ShaderLanguage::TYPE_VEC2;
actions[VS::SHADER_SPATIAL].renames["POINT_COORD"] = "gl_PointCoord";
actions[VS::SHADER_SPATIAL].renames["INSTANCE_CUSTOM"] = "instance_custom";
actions[VS::SHADER_SPATIAL].renames["SCREEN_UV"] = "screen_uv";
@@ -894,10 +895,9 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_SPATIAL].usage_defines["DIFFUSE_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
actions[VS::SHADER_SPATIAL].usage_defines["SPECULAR_LIGHT"] = "#define USE_LIGHT_SHADER_CODE\n";
- actions[VS::SHADER_SPATIAL].renames["SSS_STRENGTH"] = "sss_strength";
-
actions[VS::SHADER_SPATIAL].render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["world_vertex_coords"] = "#define VERTEX_WORLD_COORDS_USED\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["ensure_correct_normals"] = "#define ENSURE_CORRECT_NORMALS\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["cull_front"] = "#define DO_SIDE_CHECK\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["cull_disabled"] = "#define DO_SIDE_CHECK\n";
@@ -912,6 +912,7 @@ ShaderCompilerGLES3::ShaderCompilerGLES3() {
actions[VS::SHADER_SPATIAL].render_mode_defines["specular_toon"] = "#define SPECULAR_TOON\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["specular_disabled"] = "#define SPECULAR_DISABLED\n";
actions[VS::SHADER_SPATIAL].render_mode_defines["shadows_disabled"] = "#define SHADOWS_DISABLED\n";
+ actions[VS::SHADER_SPATIAL].render_mode_defines["ambient_light_disabled"] = "#define AMBIENT_LIGHT_DISABLED\n";
/* PARTICLES SHADER */
diff --git a/drivers/gles3/shader_compiler_gles3.h b/drivers/gles3/shader_compiler_gles3.h
index bf776ee062..7a32057741 100644
--- a/drivers/gles3/shader_compiler_gles3.h
+++ b/drivers/gles3/shader_compiler_gles3.h
@@ -52,6 +52,7 @@ public:
Vector<CharString> defines;
Vector<StringName> texture_uniforms;
+ Vector<ShaderLanguage::DataType> texture_types;
Vector<ShaderLanguage::ShaderNode::Uniform::Hint> texture_hints;
Vector<uint32_t> uniform_offsets;
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index 08b8a1cc26..007600bb42 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -240,8 +240,6 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() {
CharString code_globals;
CharString material_string;
- //print_line("code version? "+itos(conditional_version.code_version));
-
CustomCode *cc = NULL;
if (conditional_version.code_version > 0) {
@@ -554,7 +552,7 @@ ShaderGLES3::Version *ShaderGLES3::get_current_version() {
v.texture_uniform_locations.resize(cc->texture_uniforms.size());
for (int i = 0; i < cc->texture_uniforms.size(); i++) {
- v.texture_uniform_locations[i] = glGetUniformLocation(v.id, String(cc->texture_uniforms[i]).ascii().get_data());
+ v.texture_uniform_locations.write[i] = glGetUniformLocation(v.id, String(cc->texture_uniforms[i]).ascii().get_data());
glUniform1i(v.texture_uniform_locations[i], i + base_material_tex_index);
}
}
@@ -743,13 +741,6 @@ void ShaderGLES3::set_custom_shader(uint32_t p_code_id) {
void ShaderGLES3::free_custom_shader(uint32_t p_code_id) {
- /* if (! custom_code_map.has( p_code_id )) {
- print_line("no code id "+itos(p_code_id));
- } else {
- print_line("freed code id "+itos(p_code_id));
-
- }*/
-
ERR_FAIL_COND(!custom_code_map.has(p_code_id));
if (conditional_version.code_version == p_code_id)
conditional_version.code_version = 0; //bye
diff --git a/drivers/gles3/shaders/blend_shape.glsl b/drivers/gles3/shaders/blend_shape.glsl
index 4e0d066823..a1e954e33d 100644
--- a/drivers/gles3/shaders/blend_shape.glsl
+++ b/drivers/gles3/shaders/blend_shape.glsl
@@ -1,6 +1,6 @@
+/* clang-format off */
[vertex]
-
/*
from VisualServer:
@@ -23,56 +23,57 @@ ARRAY_INDEX=8,
/* INPUT ATTRIBS */
-layout(location=0) in highp VFORMAT vertex_attrib;
-layout(location=1) in vec3 normal_attrib;
+layout(location = 0) in highp VFORMAT vertex_attrib;
+/* clang-format on */
+layout(location = 1) in vec3 normal_attrib;
#ifdef ENABLE_TANGENT
-layout(location=2) in vec4 tangent_attrib;
+layout(location = 2) in vec4 tangent_attrib;
#endif
#ifdef ENABLE_COLOR
-layout(location=3) in vec4 color_attrib;
+layout(location = 3) in vec4 color_attrib;
#endif
#ifdef ENABLE_UV
-layout(location=4) in vec2 uv_attrib;
+layout(location = 4) in vec2 uv_attrib;
#endif
#ifdef ENABLE_UV2
-layout(location=5) in vec2 uv2_attrib;
+layout(location = 5) in vec2 uv2_attrib;
#endif
#ifdef ENABLE_SKELETON
-layout(location=6) in ivec4 bone_attrib;
-layout(location=7) in vec4 weight_attrib;
+layout(location = 6) in ivec4 bone_attrib;
+layout(location = 7) in vec4 weight_attrib;
#endif
/* BLEND ATTRIBS */
#ifdef ENABLE_BLEND
-layout(location=8) in highp VFORMAT vertex_attrib_blend;
-layout(location=9) in vec3 normal_attrib_blend;
+layout(location = 8) in highp VFORMAT vertex_attrib_blend;
+layout(location = 9) in vec3 normal_attrib_blend;
#ifdef ENABLE_TANGENT
-layout(location=10) in vec4 tangent_attrib_blend;
+layout(location = 10) in vec4 tangent_attrib_blend;
#endif
#ifdef ENABLE_COLOR
-layout(location=11) in vec4 color_attrib_blend;
+layout(location = 11) in vec4 color_attrib_blend;
#endif
#ifdef ENABLE_UV
-layout(location=12) in vec2 uv_attrib_blend;
+layout(location = 12) in vec2 uv_attrib_blend;
#endif
#ifdef ENABLE_UV2
-layout(location=13) in vec2 uv2_attrib_blend;
+layout(location = 13) in vec2 uv2_attrib_blend;
#endif
#ifdef ENABLE_SKELETON
-layout(location=14) in ivec4 bone_attrib_blend;
-layout(location=15) in vec4 weight_attrib_blend;
+layout(location = 14) in ivec4 bone_attrib_blend;
+layout(location = 15) in vec4 weight_attrib_blend;
#endif
#endif
@@ -110,7 +111,6 @@ uniform float blend_amount;
void main() {
-
#ifdef ENABLE_BLEND
vertex_out = vertex_attrib_blend + vertex_attrib * blend_amount;
@@ -140,7 +140,6 @@ void main() {
uv2_out = uv2_attrib_blend + uv2_attrib * blend_amount;
#endif
-
#ifdef ENABLE_SKELETON
bone_out = bone_attrib_blend;
@@ -149,7 +148,6 @@ void main() {
#else //ENABLE_BLEND
-
vertex_out = vertex_attrib * blend_amount;
#ifdef ENABLE_NORMAL
@@ -177,7 +175,6 @@ void main() {
uv2_out = uv2_attrib * blend_amount;
#endif
-
#ifdef ENABLE_SKELETON
bone_out = bone_attrib;
@@ -188,10 +185,10 @@ void main() {
gl_Position = vec4(0.0);
}
+/* clang-format off */
[fragment]
-
void main() {
}
-
+/* clang-format on */
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 326aab4c7c..53f563303a 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -1,12 +1,13 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec2 vertex;
-layout(location=3) in vec4 color_attrib;
+layout(location = 0) in highp vec2 vertex;
+/* clang-format on */
+layout(location = 3) in vec4 color_attrib;
#ifdef USE_SKELETON
-layout(location=6) in uvec4 bone_indices; // attrib:6
-layout(location=7) in vec4 bone_weights; // attrib:7
+layout(location = 6) in uvec4 bone_indices; // attrib:6
+layout(location = 7) in vec4 bone_weights; // attrib:7
#endif
#ifdef USE_TEXTURE_RECT
@@ -18,25 +19,24 @@ uniform vec4 src_rect;
#ifdef USE_INSTANCING
-layout(location=8) in highp vec4 instance_xform0;
-layout(location=9) in highp vec4 instance_xform1;
-layout(location=10) in highp vec4 instance_xform2;
-layout(location=11) in lowp vec4 instance_color;
+layout(location = 8) in highp vec4 instance_xform0;
+layout(location = 9) in highp vec4 instance_xform1;
+layout(location = 10) in highp vec4 instance_xform2;
+layout(location = 11) in lowp vec4 instance_color;
#ifdef USE_INSTANCE_CUSTOM
-layout(location=12) in highp vec4 instance_custom_data;
+layout(location = 12) in highp vec4 instance_custom_data;
#endif
#endif
-layout(location=4) in highp vec2 uv_attrib;
+layout(location = 4) in highp vec2 uv_attrib;
-//skeletn
+// skeleton
#endif
uniform highp vec2 color_texpixel_size;
-
layout(std140) uniform CanvasItemData { //ubo:0
highp mat4 projection_matrix;
@@ -46,7 +46,6 @@ layout(std140) uniform CanvasItemData { //ubo:0
uniform highp mat4 modelview_matrix;
uniform highp mat4 extra_matrix;
-
out highp vec2 uv_interp;
out mediump vec4 color_interp;
@@ -55,7 +54,6 @@ out mediump vec4 color_interp;
out highp vec2 pixel_size_interp;
#endif
-
#ifdef USE_SKELETON
uniform mediump sampler2D skeleton_texture; // texunit:-1
uniform highp mat4 skeleton_transform;
@@ -66,7 +64,7 @@ uniform highp mat4 skeleton_transform_inverse;
layout(std140) uniform LightData { //ubo:1
- //light matrices
+ // light matrices
highp mat4 light_matrix;
highp mat4 light_local_matrix;
highp mat4 shadow_matrix;
@@ -80,9 +78,8 @@ layout(std140) uniform LightData { //ubo:1
highp float shadow_distance_mult;
};
-
out vec4 light_uv_interp;
-
+out vec2 transformed_light_uv;
out vec4 local_rot;
@@ -100,27 +97,31 @@ uniform int h_frames;
uniform int v_frames;
#endif
-
#if defined(USE_MATERIAL)
+/* clang-format off */
layout(std140) uniform UniformData { //ubo:2
MATERIAL_UNIFORMS
};
+/* clang-format on */
#endif
+/* clang-format off */
VERTEX_SHADER_GLOBALS
+/* clang-format on */
+
void main() {
vec4 color = color_attrib;
#ifdef USE_INSTANCING
- mat4 extra_matrix2 = extra_matrix * transpose(mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0)));
- color*=instance_color;
+ mat4 extra_matrix2 = extra_matrix * transpose(mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0)));
+ color *= instance_color;
vec4 instance_custom = instance_custom_data;
#else
@@ -135,41 +136,40 @@ void main() {
} else {
uv_interp = src_rect.xy + abs(src_rect.zw) * vertex;
}
- highp vec4 outvec = vec4(dst_rect.xy + abs(dst_rect.zw) * mix(vertex,vec2(1.0,1.0)-vertex,lessThan(src_rect.zw,vec2(0.0,0.0))),0.0,1.0);
+ highp vec4 outvec = vec4(dst_rect.xy + abs(dst_rect.zw) * mix(vertex, vec2(1.0, 1.0) - vertex, lessThan(src_rect.zw, vec2(0.0, 0.0))), 0.0, 1.0);
#else
uv_interp = uv_attrib;
- highp vec4 outvec = vec4(vertex,0.0,1.0);
+ highp vec4 outvec = vec4(vertex, 0.0, 1.0);
#endif
-
#ifdef USE_PARTICLES
//scale by texture size
- outvec.xy/=color_texpixel_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);
+ 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_matrix2
-{
+ {
+ /* clang-format off */
VERTEX_SHADER_CODE
-}
-
+ /* clang-format on */
+ }
#ifdef USE_NINEPATCH
- pixel_size_interp=abs(dst_rect.zw) * vertex;
+ pixel_size_interp = abs(dst_rect.zw) * vertex;
#endif
#if !defined(SKIP_TRANSFORM_USED)
@@ -183,47 +183,46 @@ VERTEX_SHADER_CODE
#ifdef USE_PIXEL_SNAP
- outvec.xy=floor(outvec+0.5).xy;
+ outvec.xy = floor(outvec + 0.5).xy;
#endif
-
#ifdef USE_SKELETON
- if (bone_weights!=vec4(0.0)){ //must be a valid bone
+ if (bone_weights != vec4(0.0)) { //must be a valid bone
//skeleton transform
ivec4 bone_indicesi = ivec4(bone_indices);
- ivec2 tex_ofs = ivec2( bone_indicesi.x%256, (bone_indicesi.x/256)*2 );
-
- highp mat2x4 m = mat2x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0)
- ) * bone_weights.x;
+ ivec2 tex_ofs = ivec2(bone_indicesi.x % 256, (bone_indicesi.x / 256) * 2);
- tex_ofs = ivec2( bone_indicesi.y%256, (bone_indicesi.y/256)*2 );
+ highp mat2x4 m;
+ m = mat2x4(
+ texelFetch(skeleton_texture, tex_ofs, 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) *
+ bone_weights.x;
- m+= mat2x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0)
- ) * bone_weights.y;
+ tex_ofs = ivec2(bone_indicesi.y % 256, (bone_indicesi.y / 256) * 2);
- tex_ofs = ivec2( bone_indicesi.z%256, (bone_indicesi.z/256)*2 );
+ m += mat2x4(
+ texelFetch(skeleton_texture, tex_ofs, 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) *
+ bone_weights.y;
- m+= mat2x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0)
- ) * bone_weights.z;
+ tex_ofs = ivec2(bone_indicesi.z % 256, (bone_indicesi.z / 256) * 2);
+ m += mat2x4(
+ texelFetch(skeleton_texture, tex_ofs, 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) *
+ bone_weights.z;
- tex_ofs = ivec2( bone_indicesi.w%256, (bone_indicesi.w/256)*2 );
+ tex_ofs = ivec2(bone_indicesi.w % 256, (bone_indicesi.w / 256) * 2);
- m+= mat2x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0)
- ) * bone_weights.w;
+ m += mat2x4(
+ texelFetch(skeleton_texture, tex_ofs, 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0)) *
+ bone_weights.w;
- mat4 bone_matrix = skeleton_transform * transpose(mat4(m[0],m[1],vec4(0.0,0.0,1.0,0.0),vec4(0.0,0.0,0.0,1.0))) * skeleton_transform_inverse;
+ mat4 bone_matrix = skeleton_transform * transpose(mat4(m[0], m[1], vec4(0.0, 0.0, 1.0, 0.0), vec4(0.0, 0.0, 0.0, 1.0))) * skeleton_transform_inverse;
outvec = bone_matrix * outvec;
}
@@ -235,38 +234,39 @@ VERTEX_SHADER_CODE
#ifdef USE_LIGHTING
light_uv_interp.xy = (light_matrix * outvec).xy;
- light_uv_interp.zw =(light_local_matrix * outvec).xy;
+ light_uv_interp.zw = (light_local_matrix * outvec).xy;
+
+ mat3 inverse_light_matrix = mat3(inverse(light_matrix));
+ inverse_light_matrix[0] = normalize(inverse_light_matrix[0]);
+ inverse_light_matrix[1] = normalize(inverse_light_matrix[1]);
+ inverse_light_matrix[2] = normalize(inverse_light_matrix[2]);
+ transformed_light_uv = (inverse_light_matrix * vec3(light_uv_interp.zw, 0.0)).xy; //for normal mapping
+
#ifdef USE_SHADOWS
- pos=outvec.xy;
+ pos = outvec.xy;
#endif
-
- local_rot.xy=normalize( (modelview_matrix * ( extra_matrix * vec4(1.0,0.0,0.0,0.0) )).xy );
- local_rot.zw=normalize( (modelview_matrix * ( extra_matrix * vec4(0.0,1.0,0.0,0.0) )).xy );
+ local_rot.xy = normalize((modelview_matrix * (extra_matrix * vec4(1.0, 0.0, 0.0, 0.0))).xy);
+ local_rot.zw = normalize((modelview_matrix * (extra_matrix * vec4(0.0, 1.0, 0.0, 0.0))).xy);
#ifdef USE_TEXTURE_RECT
- local_rot.xy*=sign(src_rect.z);
- local_rot.zw*=sign(src_rect.w);
+ local_rot.xy *= sign(src_rect.z);
+ local_rot.zw *= sign(src_rect.w);
#endif
-
-
#endif
-
}
+/* clang-format off */
[fragment]
-
-
uniform mediump sampler2D color_texture; // texunit:0
+/* clang-format on */
uniform highp vec2 color_texpixel_size;
uniform mediump sampler2D normal_texture; // texunit:1
-
in highp vec2 uv_interp;
in mediump vec4 color_interp;
-
#if defined(SCREEN_TEXTURE_USED)
uniform sampler2D screen_texture; // texunit:-3
@@ -284,7 +284,6 @@ layout(std140) uniform CanvasItemData {
highp float time;
};
-
#ifdef USE_LIGHTING
layout(std140) uniform LightData {
@@ -304,11 +303,10 @@ layout(std140) uniform LightData {
uniform lowp sampler2D light_texture; // texunit:-1
in vec4 light_uv_interp;
-
+in vec2 transformed_light_uv;
in vec4 local_rot;
-
#ifdef USE_SHADOWS
uniform highp sampler2D shadow_texture; // texunit:-2
@@ -323,44 +321,49 @@ const bool at_light_pass = false;
uniform mediump vec4 final_modulate;
-
-
-
-layout(location=0) out mediump vec4 frag_color;
-
+layout(location = 0) out mediump vec4 frag_color;
#if defined(USE_MATERIAL)
+/* clang-format off */
layout(std140) uniform UniformData {
MATERIAL_UNIFORMS
};
+/* clang-format on */
#endif
+/* clang-format off */
+
FRAGMENT_SHADER_GLOBALS
+/* clang-format on */
+
void light_compute(
- inout vec4 light,
- inout vec2 light_vec,
- inout float light_height,
- inout vec4 light_color,
- vec2 light_uv,
- inout vec4 shadow_color,
- vec3 normal,
- vec2 uv,
+ inout vec4 light,
+ inout vec2 light_vec,
+ inout float light_height,
+ inout vec4 light_color,
+ vec2 light_uv,
+ inout vec4 shadow_color,
+ vec3 normal,
+ vec2 uv,
#if defined(SCREEN_UV_USED)
- vec2 screen_uv,
+ vec2 screen_uv,
#endif
- vec4 color) {
+ vec4 color) {
#if defined(USE_LIGHT_SHADER_CODE)
+ /* clang-format off */
+
LIGHT_SHADER_CODE
-#endif
+ /* clang-format on */
+#endif
}
#ifdef USE_TEXTURE_RECT
@@ -376,48 +379,44 @@ in highp vec2 pixel_size_interp;
uniform int np_repeat_v;
uniform int np_repeat_h;
uniform bool np_draw_center;
-//left top right bottom in pixel coordinates
+// left top right bottom in pixel coordinates
uniform vec4 np_margins;
+float map_ninepatch_axis(float pixel, float draw_size, float tex_pixel_size, float margin_begin, float margin_end, int np_repeat, inout int draw_center) {
-
-float map_ninepatch_axis(float pixel, float draw_size,float tex_pixel_size,float margin_begin,float margin_end,int np_repeat,inout int draw_center) {
-
-
- float tex_size = 1.0/tex_pixel_size;
+ float tex_size = 1.0 / tex_pixel_size;
if (pixel < margin_begin) {
return pixel * tex_pixel_size;
- } else if (pixel >= draw_size-margin_end) {
- return (tex_size-(draw_size-pixel)) * tex_pixel_size;
+ } else if (pixel >= draw_size - margin_end) {
+ return (tex_size - (draw_size - pixel)) * tex_pixel_size;
} else {
- if (!np_draw_center){
+ if (!np_draw_center) {
draw_center--;
}
- if (np_repeat==0) { //stretch
+ if (np_repeat == 0) { //stretch
//convert to ratio
float ratio = (pixel - margin_begin) / (draw_size - margin_begin - margin_end);
//scale to source texture
return (margin_begin + ratio * (tex_size - margin_begin - margin_end)) * tex_pixel_size;
- } else if (np_repeat==1) { //tile
+ } else if (np_repeat == 1) { //tile
//convert to ratio
float ofs = mod((pixel - margin_begin), tex_size - margin_begin - margin_end);
//scale to source texture
return (margin_begin + ofs) * tex_pixel_size;
- } else if (np_repeat==2) { //tile fit
+ } else if (np_repeat == 2) { //tile fit
//convert to ratio
float src_area = draw_size - margin_begin - margin_end;
float dst_area = tex_size - margin_begin - margin_end;
- float scale = max(1.0,floor(src_area / max(dst_area,0.0000001) + 0.5));
+ float scale = max(1.0, floor(src_area / max(dst_area, 0.0000001) + 0.5));
//convert to ratio
float ratio = (pixel - margin_begin) / src_area;
- ratio = mod(ratio * scale,1.0);
+ ratio = mod(ratio * scale, 1.0);
return (margin_begin + ratio * dst_area) * tex_pixel_size;
}
}
-
}
#endif
@@ -434,42 +433,39 @@ void main() {
#ifdef USE_NINEPATCH
- int draw_center=2;
+ int draw_center = 2;
uv = vec2(
- map_ninepatch_axis(pixel_size_interp.x,abs(dst_rect.z),color_texpixel_size.x,np_margins.x,np_margins.z,np_repeat_h,draw_center),
- map_ninepatch_axis(pixel_size_interp.y,abs(dst_rect.w),color_texpixel_size.y,np_margins.y,np_margins.w,np_repeat_v,draw_center)
- );
+ map_ninepatch_axis(pixel_size_interp.x, abs(dst_rect.z), color_texpixel_size.x, np_margins.x, np_margins.z, np_repeat_h, draw_center),
+ map_ninepatch_axis(pixel_size_interp.y, abs(dst_rect.w), color_texpixel_size.y, np_margins.y, np_margins.w, np_repeat_v, draw_center));
- if (draw_center==0) {
- color.a=0.0;
+ if (draw_center == 0) {
+ color.a = 0.0;
}
- uv = uv*src_rect.zw+src_rect.xy; //apply region if needed
+ uv = uv * src_rect.zw + src_rect.xy; //apply region if needed
#endif
if (clip_rect_uv) {
- uv = clamp(uv,src_rect.xy,src_rect.xy+abs(src_rect.zw));
+ uv = clamp(uv, src_rect.xy, src_rect.xy + abs(src_rect.zw));
}
#endif
#if !defined(COLOR_USED)
-//default behavior, texture by color
+ //default behavior, texture by color
#ifdef USE_DISTANCE_FIELD
- const float smoothing = 1.0/32.0;
- float distance = textureLod(color_texture, uv,0.0).a;
+ const float smoothing = 1.0 / 32.0;
+ float distance = textureLod(color_texture, uv, 0.0).a;
color.a = smoothstep(0.5 - smoothing, 0.5 + smoothing, distance) * color.a;
#else
- color *= texture( color_texture, uv );
+ color *= texture(color_texture, uv);
#endif
#endif
-
-
vec3 normal;
#if defined(NORMAL_USED)
@@ -480,60 +476,56 @@ void main() {
#endif
if (use_default_normal) {
- normal.xy = textureLod(normal_texture, uv,0.0).xy * 2.0 - 1.0;
- normal.z = sqrt(1.0-dot(normal.xy,normal.xy));
- normal_used=true;
+ normal.xy = textureLod(normal_texture, uv, 0.0).xy * 2.0 - 1.0;
+ normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
+ normal_used = true;
} else {
- normal = vec3(0.0,0.0,1.0);
+ normal = vec3(0.0, 0.0, 1.0);
}
-
-
#if defined(SCREEN_UV_USED)
- vec2 screen_uv = gl_FragCoord.xy*screen_pixel_size;
+ vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
#endif
-
-{
- float normal_depth=1.0;
+ {
+ float normal_depth = 1.0;
#if defined(NORMALMAP_USED)
- vec3 normal_map=vec3(0.0,0.0,1.0);
+ vec3 normal_map = vec3(0.0, 0.0, 1.0);
#endif
+ /* clang-format off */
+
FRAGMENT_SHADER_CODE
+ /* clang-format on */
+
#if defined(NORMALMAP_USED)
- normal = mix(vec3(0.0,0.0,1.0), normal_map * vec3(2.0,-2.0,1.0) - vec3( 1.0, -1.0, 0.0 ), normal_depth );
+ normal = mix(vec3(0.0, 0.0, 1.0), normal_map * vec3(2.0, -2.0, 1.0) - vec3(1.0, -1.0, 0.0), normal_depth);
#endif
-
-}
+ }
#ifdef DEBUG_ENCODED_32
- highp float enc32 = dot( color,highp vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) );
- color = vec4(vec3(enc32),1.0);
+ highp float enc32 = dot(color, highp vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1));
+ color = vec4(vec3(enc32), 1.0);
#endif
-
- color*=final_modulate;
-
-
-
+ color *= final_modulate;
#ifdef USE_LIGHTING
- vec2 light_vec = light_uv_interp.zw;; //for shadow and normal mapping
+ vec2 light_vec = transformed_light_uv;
if (normal_used) {
- normal.xy = mat2(local_rot.xy,local_rot.zw) * normal.xy;
+ normal.xy = mat2(local_rot.xy, local_rot.zw) * normal.xy;
}
- float att=1.0;
+ float att = 1.0;
vec2 light_uv = light_uv_interp.xy;
- vec4 light = texture(light_texture,light_uv);
+ vec4 light = texture(light_texture, light_uv);
- if (any(lessThan(light_uv_interp.xy,vec2(0.0,0.0))) || any(greaterThanEqual(light_uv_interp.xy,vec2(1.0,1.0)))) {
- color.a*=light_outside_alpha; //invisible
+ if (any(lessThan(light_uv_interp.xy, vec2(0.0, 0.0))) || any(greaterThanEqual(light_uv_interp.xy, vec2(1.0, 1.0)))) {
+ color.a *= light_outside_alpha; //invisible
} else {
float real_light_height = light_height;
@@ -541,178 +533,176 @@ FRAGMENT_SHADER_CODE
vec4 real_light_shadow_color = light_shadow_color;
#if defined(USE_LIGHT_SHADER_CODE)
-//light is written by the light shader
+ //light is written by the light shader
light_compute(
- light,
- light_vec,
- real_light_height,
- real_light_color,
- light_uv,
- real_light_shadow_color,
- normal,
- uv,
+ light,
+ light_vec,
+ real_light_height,
+ real_light_color,
+ light_uv,
+ real_light_shadow_color,
+ normal,
+ uv,
#if defined(SCREEN_UV_USED)
- screen_uv,
+ screen_uv,
#endif
- color);
+ color);
#endif
light *= real_light_color;
if (normal_used) {
- vec3 light_normal = normalize(vec3(light_vec,-real_light_height));
- light*=max(dot(-light_normal,normal),0.0);
+ vec3 light_normal = normalize(vec3(light_vec, -real_light_height));
+ light *= max(dot(-light_normal, normal), 0.0);
}
- color*=light;
+ color *= light;
#ifdef USE_SHADOWS
-
- float angle_to_light = -atan(light_vec.x,light_vec.y);
+ light_vec = light_uv_interp.zw; //for shadows
+ float angle_to_light = -atan(light_vec.x, light_vec.y);
float PI = 3.14159265358979323846264;
/*int i = int(mod(floor((angle_to_light+7.0*PI/6.0)/(4.0*PI/6.0))+1.0, 3.0)); // +1 pq os indices estao em ordem 2,0,1 nos arrays
float ang*/
- float su,sz;
+ float su, sz;
float abs_angle = abs(angle_to_light);
vec2 point;
float sh;
- if (abs_angle<45.0*PI/180.0) {
+ if (abs_angle < 45.0 * PI / 180.0) {
point = light_vec;
- sh=0.0+(1.0/8.0);
- } else if (abs_angle>135.0*PI/180.0) {
+ sh = 0.0 + (1.0 / 8.0);
+ } else if (abs_angle > 135.0 * PI / 180.0) {
point = -light_vec;
- sh = 0.5+(1.0/8.0);
- } else if (angle_to_light>0.0) {
+ sh = 0.5 + (1.0 / 8.0);
+ } else if (angle_to_light > 0.0) {
- point = vec2(light_vec.y,-light_vec.x);
- sh = 0.25+(1.0/8.0);
+ point = vec2(light_vec.y, -light_vec.x);
+ sh = 0.25 + (1.0 / 8.0);
} else {
- point = vec2(-light_vec.y,light_vec.x);
- sh = 0.75+(1.0/8.0);
-
+ point = vec2(-light_vec.y, light_vec.x);
+ sh = 0.75 + (1.0 / 8.0);
}
-
- highp vec4 s = shadow_matrix * vec4(point,0.0,1.0);
- s.xyz/=s.w;
- su=s.x*0.5+0.5;
- sz=s.z*0.5+0.5;
+ highp vec4 s = shadow_matrix * vec4(point, 0.0, 1.0);
+ s.xyz /= s.w;
+ su = s.x * 0.5 + 0.5;
+ sz = s.z * 0.5 + 0.5;
//sz=lightlength(light_vec);
- highp float shadow_attenuation=0.0;
+ highp float shadow_attenuation = 0.0;
#ifdef USE_RGBA_SHADOWS
-#define SHADOW_DEPTH(m_tex,m_uv) dot(texture((m_tex),(m_uv)),vec4(1.0 / (256.0 * 256.0 * 256.0),1.0 / (256.0 * 256.0),1.0 / 256.0,1) )
+#define SHADOW_DEPTH(m_tex, m_uv) dot(texture((m_tex), (m_uv)), vec4(1.0 / (256.0 * 256.0 * 256.0), 1.0 / (256.0 * 256.0), 1.0 / 256.0, 1))
#else
-#define SHADOW_DEPTH(m_tex,m_uv) (texture((m_tex),(m_uv)).r)
+#define SHADOW_DEPTH(m_tex, m_uv) (texture((m_tex), (m_uv)).r)
#endif
-
-
#ifdef SHADOW_USE_GRADIENT
-#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture,vec2(m_ofs,sh)); shadow_attenuation+=1.0-smoothstep(sd,sd+shadow_gradient,sz); }
+#define SHADOW_TEST(m_ofs) \
+ { \
+ highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); \
+ shadow_attenuation += 1.0 - smoothstep(sd, sd + shadow_gradient, sz); \
+ }
#else
-#define SHADOW_TEST(m_ofs) { highp float sd = SHADOW_DEPTH(shadow_texture,vec2(m_ofs,sh)); shadow_attenuation+=step(sz,sd); }
+#define SHADOW_TEST(m_ofs) \
+ { \
+ highp float sd = SHADOW_DEPTH(shadow_texture, vec2(m_ofs, sh)); \
+ shadow_attenuation += step(sz, sd); \
+ }
#endif
-
#ifdef SHADOW_FILTER_NEAREST
SHADOW_TEST(su);
#endif
-
#ifdef SHADOW_FILTER_PCF3
- SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su + shadowpixel_size);
SHADOW_TEST(su);
- SHADOW_TEST(su-shadowpixel_size);
- shadow_attenuation/=3.0;
+ SHADOW_TEST(su - shadowpixel_size);
+ shadow_attenuation /= 3.0;
#endif
-
#ifdef SHADOW_FILTER_PCF5
- SHADOW_TEST(su+shadowpixel_size*2.0);
- SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su + shadowpixel_size * 2.0);
+ SHADOW_TEST(su + shadowpixel_size);
SHADOW_TEST(su);
- SHADOW_TEST(su-shadowpixel_size);
- SHADOW_TEST(su-shadowpixel_size*2.0);
- shadow_attenuation/=5.0;
+ SHADOW_TEST(su - shadowpixel_size);
+ SHADOW_TEST(su - shadowpixel_size * 2.0);
+ shadow_attenuation /= 5.0;
#endif
-
#ifdef SHADOW_FILTER_PCF7
- SHADOW_TEST(su+shadowpixel_size*3.0);
- SHADOW_TEST(su+shadowpixel_size*2.0);
- SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su + shadowpixel_size * 3.0);
+ SHADOW_TEST(su + shadowpixel_size * 2.0);
+ SHADOW_TEST(su + shadowpixel_size);
SHADOW_TEST(su);
- SHADOW_TEST(su-shadowpixel_size);
- SHADOW_TEST(su-shadowpixel_size*2.0);
- SHADOW_TEST(su-shadowpixel_size*3.0);
- shadow_attenuation/=7.0;
+ SHADOW_TEST(su - shadowpixel_size);
+ SHADOW_TEST(su - shadowpixel_size * 2.0);
+ SHADOW_TEST(su - shadowpixel_size * 3.0);
+ shadow_attenuation /= 7.0;
#endif
-
#ifdef SHADOW_FILTER_PCF9
- SHADOW_TEST(su+shadowpixel_size*4.0);
- SHADOW_TEST(su+shadowpixel_size*3.0);
- SHADOW_TEST(su+shadowpixel_size*2.0);
- SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su + shadowpixel_size * 4.0);
+ SHADOW_TEST(su + shadowpixel_size * 3.0);
+ SHADOW_TEST(su + shadowpixel_size * 2.0);
+ SHADOW_TEST(su + shadowpixel_size);
SHADOW_TEST(su);
- SHADOW_TEST(su-shadowpixel_size);
- SHADOW_TEST(su-shadowpixel_size*2.0);
- SHADOW_TEST(su-shadowpixel_size*3.0);
- SHADOW_TEST(su-shadowpixel_size*4.0);
- shadow_attenuation/=9.0;
+ SHADOW_TEST(su - shadowpixel_size);
+ SHADOW_TEST(su - shadowpixel_size * 2.0);
+ SHADOW_TEST(su - shadowpixel_size * 3.0);
+ SHADOW_TEST(su - shadowpixel_size * 4.0);
+ shadow_attenuation /= 9.0;
#endif
#ifdef SHADOW_FILTER_PCF13
- SHADOW_TEST(su+shadowpixel_size*6.0);
- SHADOW_TEST(su+shadowpixel_size*5.0);
- SHADOW_TEST(su+shadowpixel_size*4.0);
- SHADOW_TEST(su+shadowpixel_size*3.0);
- SHADOW_TEST(su+shadowpixel_size*2.0);
- SHADOW_TEST(su+shadowpixel_size);
+ SHADOW_TEST(su + shadowpixel_size * 6.0);
+ SHADOW_TEST(su + shadowpixel_size * 5.0);
+ SHADOW_TEST(su + shadowpixel_size * 4.0);
+ SHADOW_TEST(su + shadowpixel_size * 3.0);
+ SHADOW_TEST(su + shadowpixel_size * 2.0);
+ SHADOW_TEST(su + shadowpixel_size);
SHADOW_TEST(su);
- SHADOW_TEST(su-shadowpixel_size);
- SHADOW_TEST(su-shadowpixel_size*2.0);
- SHADOW_TEST(su-shadowpixel_size*3.0);
- SHADOW_TEST(su-shadowpixel_size*4.0);
- SHADOW_TEST(su-shadowpixel_size*5.0);
- SHADOW_TEST(su-shadowpixel_size*6.0);
- shadow_attenuation/=13.0;
+ SHADOW_TEST(su - shadowpixel_size);
+ SHADOW_TEST(su - shadowpixel_size * 2.0);
+ SHADOW_TEST(su - shadowpixel_size * 3.0);
+ SHADOW_TEST(su - shadowpixel_size * 4.0);
+ SHADOW_TEST(su - shadowpixel_size * 5.0);
+ SHADOW_TEST(su - shadowpixel_size * 6.0);
+ shadow_attenuation /= 13.0;
#endif
- //color*=shadow_attenuation;
- color=mix(real_light_shadow_color,color,shadow_attenuation);
+ //color *= shadow_attenuation;
+ color = mix(real_light_shadow_color, color, shadow_attenuation);
//use shadows
#endif
}
//use lighting
#endif
- //color.rgb*=color.a;
+ //color.rgb *= color.a;
frag_color = color;
-
}
diff --git a/drivers/gles3/shaders/canvas_shadow.glsl b/drivers/gles3/shaders/canvas_shadow.glsl
index c757990de0..68d0713385 100644
--- a/drivers/gles3/shaders/canvas_shadow.glsl
+++ b/drivers/gles3/shaders/canvas_shadow.glsl
@@ -1,49 +1,45 @@
+/* clang-format off */
[vertex]
-
-
uniform highp mat4 projection_matrix;
+/* clang-format on */
uniform highp mat4 light_matrix;
uniform highp mat4 world_matrix;
uniform highp float distance_norm;
-layout(location=0) in highp vec3 vertex;
+layout(location = 0) in highp vec3 vertex;
out highp vec4 position_interp;
void main() {
- gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex,1.0)));
- position_interp=gl_Position;
+ gl_Position = projection_matrix * (light_matrix * (world_matrix * vec4(vertex, 1.0)));
+ position_interp = gl_Position;
}
+/* clang-format off */
[fragment]
in highp vec4 position_interp;
+/* clang-format on */
#ifdef USE_RGBA_SHADOWS
-
-layout(location=0) out lowp vec4 distance_buf;
-
+layout(location = 0) out lowp vec4 distance_buf;
#else
-
-layout(location=0) out highp float distance_buf;
-
+layout(location = 0) out highp float distance_buf;
#endif
void main() {
- highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0;//bias;
+ highp float depth = ((position_interp.z / position_interp.w) + 1.0) * 0.5 + 0.0; // bias
#ifdef USE_RGBA_SHADOWS
highp vec4 comp = fract(depth * vec4(256.0 * 256.0 * 256.0, 256.0 * 256.0, 256.0, 1.0));
comp -= comp.xxyz * vec4(0, 1.0 / 256.0, 1.0 / 256.0, 1.0 / 256.0);
- distance_buf=comp;
+ distance_buf = comp;
#else
- distance_buf=depth;
-
+ distance_buf = depth;
#endif
}
-
diff --git a/drivers/gles3/shaders/copy.glsl b/drivers/gles3/shaders/copy.glsl
index 1b7c626d3c..a5637537d2 100644
--- a/drivers/gles3/shaders/copy.glsl
+++ b/drivers/gles3/shaders/copy.glsl
@@ -1,13 +1,14 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
-layout(location=4) in vec3 cube_in;
+layout(location = 4) in vec3 cube_in;
#else
-layout(location=4) in vec2 uv_in;
+layout(location = 4) in vec2 uv_in;
#endif
-layout(location=5) in vec2 uv2_in;
+layout(location = 5) in vec2 uv2_in;
#if defined(USE_CUBEMAP) || defined(USE_PANORAMA)
out vec3 cube_interp;
@@ -32,7 +33,7 @@ void main() {
#else
uv_interp = uv_in;
#ifdef V_FLIP
- uv_interp.y = 1.0-uv_interp.y;
+ uv_interp.y = 1.0 - uv_interp.y;
#endif
#endif
@@ -44,9 +45,9 @@ void main() {
uv_interp = copy_section.xy + uv_interp * copy_section.zw;
gl_Position.xy = (copy_section.xy + (gl_Position.xy * 0.5 + 0.5) * copy_section.zw) * 2.0 - 1.0;
#endif
-
}
+/* clang-format off */
[fragment]
#define M_PI 3.14159265359
@@ -60,6 +61,7 @@ in vec3 cube_interp;
#else
in vec2 uv_interp;
#endif
+/* clang-format on */
#ifdef USE_ASYM_PANO
uniform highp mat4 pano_transform;
@@ -72,38 +74,33 @@ uniform samplerCube source_cube; //texunit:0
uniform sampler2D source; //texunit:0
#endif
-
#ifdef USE_MULTIPLIER
uniform float multiplier;
#endif
#if defined(USE_PANORAMA) || defined(USE_ASYM_PANO)
-vec4 texturePanorama(vec3 normal,sampler2D pano ) {
+vec4 texturePanorama(vec3 normal, sampler2D pano) {
vec2 st = vec2(
- atan(normal.x, normal.z),
- acos(normal.y)
- );
-
- if(st.x < 0.0)
- st.x += M_PI*2.0;
+ atan(normal.x, normal.z),
+ acos(normal.y));
- st/=vec2(M_PI*2.0,M_PI);
+ if (st.x < 0.0)
+ st.x += M_PI * 2.0;
- return textureLod(pano,st,0.0);
+ st /= vec2(M_PI * 2.0, M_PI);
+ return textureLod(pano, st, 0.0);
}
#endif
-
uniform float stuff;
uniform vec2 pixel_size;
in vec2 uv2_interp;
-
#ifdef USE_BCS
uniform vec3 bcs;
@@ -118,20 +115,17 @@ uniform sampler2D color_correction; //texunit:1
layout(location = 0) out vec4 frag_color;
-
-
-
void main() {
//vec4 color = color_interp;
#ifdef USE_PANORAMA
- vec4 color = texturePanorama( normalize(cube_interp), source );
+ vec4 color = texturePanorama(normalize(cube_interp), source);
#elif defined(USE_ASYM_PANO)
- // When an asymmetrical projection matrix is used (applicable for stereoscopic rendering i.e. VR) we need to do this calculation per fragment to get a perspective correct result.
+ // 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.
@@ -142,72 +136,68 @@ void main() {
cube_normal = mat3(pano_transform) * cube_normal;
cube_normal.z = -cube_normal.z;
- vec4 color = texturePanorama( normalize(cube_normal.xyz), source );
+ vec4 color = texturePanorama(normalize(cube_normal.xyz), source);
#elif defined(USE_CUBEMAP)
- vec4 color = texture( source_cube, normalize(cube_interp) );
+ vec4 color = texture(source_cube, normalize(cube_interp));
#else
- vec4 color = textureLod( source, uv_interp,0.0 );
+ vec4 color = textureLod(source, uv_interp, 0.0);
#endif
-
-
#ifdef LINEAR_TO_SRGB
//regular Linear -> SRGB conversion
vec3 a = vec3(0.055);
- color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308)));
+ color.rgb = mix((vec3(1.0) + a) * pow(color.rgb, vec3(1.0 / 2.4)) - a, 12.92 * color.rgb, lessThan(color.rgb, vec3(0.0031308)));
#endif
#ifdef SRGB_TO_LINEAR
- color.rgb = mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)),vec3(2.4)),color.rgb * (1.0 / 12.92),lessThan(color.rgb,vec3(0.04045)));
+ color.rgb = mix(pow((color.rgb + vec3(0.055)) * (1.0 / (1.0 + 0.055)), vec3(2.4)), color.rgb * (1.0 / 12.92), lessThan(color.rgb, vec3(0.04045)));
#endif
#ifdef DEBUG_GRADIENT
- color.rg=uv_interp;
- color.b=0.0;
+ color.rg = uv_interp;
+ color.b = 0.0;
#endif
#ifdef DISABLE_ALPHA
- color.a=1.0;
+ color.a = 1.0;
#endif
-
#ifdef GAUSSIAN_HORIZONTAL
- color*=0.38774;
- color+=texture( source, uv_interp+vec2( 1.0, 0.0)*pixel_size )*0.24477;
- color+=texture( source, uv_interp+vec2( 2.0, 0.0)*pixel_size )*0.06136;
- color+=texture( source, uv_interp+vec2(-1.0, 0.0)*pixel_size )*0.24477;
- color+=texture( source, uv_interp+vec2(-2.0, 0.0)*pixel_size )*0.06136;
+ color *= 0.38774;
+ color += texture(source, uv_interp + vec2(1.0, 0.0) * pixel_size) * 0.24477;
+ color += texture(source, uv_interp + vec2(2.0, 0.0) * pixel_size) * 0.06136;
+ color += texture(source, uv_interp + vec2(-1.0, 0.0) * pixel_size) * 0.24477;
+ color += texture(source, uv_interp + vec2(-2.0, 0.0) * pixel_size) * 0.06136;
#endif
#ifdef GAUSSIAN_VERTICAL
- color*=0.38774;
- color+=texture( source, uv_interp+vec2( 0.0, 1.0)*pixel_size )*0.24477;
- color+=texture( source, uv_interp+vec2( 0.0, 2.0)*pixel_size )*0.06136;
- color+=texture( source, uv_interp+vec2( 0.0,-1.0)*pixel_size )*0.24477;
- color+=texture( source, uv_interp+vec2( 0.0,-2.0)*pixel_size )*0.06136;
+ color *= 0.38774;
+ color += texture(source, uv_interp + vec2(0.0, 1.0) * pixel_size) * 0.24477;
+ color += texture(source, uv_interp + vec2(0.0, 2.0) * pixel_size) * 0.06136;
+ color += texture(source, uv_interp + vec2(0.0, -1.0) * pixel_size) * 0.24477;
+ color += texture(source, uv_interp + vec2(0.0, -2.0) * pixel_size) * 0.06136;
#endif
#ifdef USE_BCS
- color.rgb = mix(vec3(0.0),color.rgb,bcs.x);
- color.rgb = mix(vec3(0.5),color.rgb,bcs.y);
- color.rgb = mix(vec3(dot(vec3(1.0),color.rgb)*0.33333),color.rgb,bcs.z);
+ color.rgb = mix(vec3(0.0), color.rgb, bcs.x);
+ color.rgb = mix(vec3(0.5), color.rgb, bcs.y);
+ color.rgb = mix(vec3(dot(vec3(1.0), color.rgb) * 0.33333), color.rgb, bcs.z);
#endif
#ifdef USE_COLOR_CORRECTION
- color.r = texture(color_correction,vec2(color.r,0.0)).r;
- color.g = texture(color_correction,vec2(color.g,0.0)).g;
- color.b = texture(color_correction,vec2(color.b,0.0)).b;
+ color.r = texture(color_correction, vec2(color.r, 0.0)).r;
+ color.g = texture(color_correction, vec2(color.g, 0.0)).g;
+ color.b = texture(color_correction, vec2(color.b, 0.0)).b;
#endif
#ifdef USE_MULTIPLIER
- color.rgb*=multiplier;
+ color.rgb *= multiplier;
#endif
frag_color = color;
}
-
diff --git a/drivers/gles3/shaders/cube_to_dp.glsl b/drivers/gles3/shaders/cube_to_dp.glsl
index 5ffc78c0b9..2b74f054f9 100644
--- a/drivers/gles3/shaders/cube_to_dp.glsl
+++ b/drivers/gles3/shaders/cube_to_dp.glsl
@@ -1,8 +1,9 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
@@ -12,10 +13,11 @@ void main() {
gl_Position = vertex_attrib;
}
+/* clang-format off */
[fragment]
-
uniform highp samplerCube source_cube; //texunit:0
+/* clang-format on */
in vec2 uv_interp;
uniform bool z_flip;
@@ -25,55 +27,53 @@ uniform highp float bias;
void main() {
- highp vec3 normal = vec3( uv_interp * 2.0 - 1.0, 0.0 );
-/*
- if(z_flip) {
- normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ highp vec3 normal = vec3(uv_interp * 2.0 - 1.0, 0.0);
+ /*
+ if (z_flip) {
+ normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
} else {
- normal.z = -0.5 + 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ normal.z = -0.5 + 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
}
-*/
+ */
- //normal.z = sqrt(1.0-dot(normal.xy,normal.xy));
- //normal.xy*=1.0+normal.z;
+ //normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
+ //normal.xy *= 1.0 + normal.z;
- normal.z = 0.5 - 0.5*((normal.x * normal.x) + (normal.y * normal.y));
+ normal.z = 0.5 - 0.5 * ((normal.x * normal.x) + (normal.y * normal.y));
+ normal = normalize(normal);
+ /*
+ normal.z = 0.5;
normal = normalize(normal);
+ */
-/*
- normal.z=0.5;
- normal=normalize(normal);
-*/
if (!z_flip) {
- normal.z=-normal.z;
+ normal.z = -normal.z;
}
- //normal = normalize(vec3( uv_interp * 2.0 - 1.0, 1.0 ));
- float depth = texture(source_cube,normal).r;
+ //normal = normalize(vec3(uv_interp * 2.0 - 1.0, 1.0));
+ float depth = texture(source_cube, normal).r;
// absolute values for direction cosines, bigger value equals closer to basis axis
vec3 unorm = abs(normal);
- if ( (unorm.x >= unorm.y) && (unorm.x >= unorm.z) ) {
- // x code
- unorm = normal.x > 0.0 ? vec3( 1.0, 0.0, 0.0 ) : vec3( -1.0, 0.0, 0.0 ) ;
- } else if ( (unorm.y > unorm.x) && (unorm.y >= unorm.z) ) {
- // y code
- unorm = normal.y > 0.0 ? vec3( 0.0, 1.0, 0.0 ) : vec3( 0.0, -1.0, 0.0 ) ;
- } else if ( (unorm.z > unorm.x) && (unorm.z > unorm.y) ) {
- // z code
- unorm = normal.z > 0.0 ? vec3( 0.0, 0.0, 1.0 ) : vec3( 0.0, 0.0, -1.0 ) ;
+ if ((unorm.x >= unorm.y) && (unorm.x >= unorm.z)) {
+ // x code
+ unorm = normal.x > 0.0 ? vec3(1.0, 0.0, 0.0) : vec3(-1.0, 0.0, 0.0);
+ } else if ((unorm.y > unorm.x) && (unorm.y >= unorm.z)) {
+ // y code
+ unorm = normal.y > 0.0 ? vec3(0.0, 1.0, 0.0) : vec3(0.0, -1.0, 0.0);
+ } else if ((unorm.z > unorm.x) && (unorm.z > unorm.y)) {
+ // z code
+ unorm = normal.z > 0.0 ? vec3(0.0, 0.0, 1.0) : vec3(0.0, 0.0, -1.0);
} else {
- // oh-no we messed up code
- // has to be
- unorm = vec3( 1.0, 0.0, 0.0 );
+ // oh-no we messed up code
+ // has to be
+ unorm = vec3(1.0, 0.0, 0.0);
}
- float depth_fix = 1.0 / dot(normal,unorm);
-
+ float depth_fix = 1.0 / dot(normal, unorm);
depth = 2.0 * depth - 1.0;
float linear_depth = 2.0 * z_near * z_far / (z_far + z_near - depth * (z_far - z_near));
- gl_FragDepth = (linear_depth*depth_fix+bias) / z_far;
+ gl_FragDepth = (linear_depth * depth_fix + bias) / z_far;
}
-
diff --git a/drivers/gles3/shaders/cubemap_filter.glsl b/drivers/gles3/shaders/cubemap_filter.glsl
index 485fbb6ee0..f65f798ff0 100644
--- a/drivers/gles3/shaders/cubemap_filter.glsl
+++ b/drivers/gles3/shaders/cubemap_filter.glsl
@@ -1,22 +1,24 @@
+/* clang-format off */
[vertex]
+layout(location = 0) in highp vec2 vertex;
+/* clang-format on */
-layout(location=0) in highp vec2 vertex;
-
-layout(location=4) in highp vec2 uv;
+layout(location = 4) in highp vec2 uv;
out highp vec2 uv_interp;
void main() {
- uv_interp=uv;
- gl_Position=vec4(vertex,0,1);
+ uv_interp = uv;
+ gl_Position = vec4(vertex, 0, 1);
}
+/* clang-format off */
[fragment]
-
precision highp float;
+/* clang-format on */
precision highp int;
#ifdef USE_SOURCE_PANORAMA
@@ -36,90 +38,85 @@ uniform int face_id;
uniform float roughness;
in highp vec2 uv_interp;
-
layout(location = 0) out vec4 frag_color;
-
#define M_PI 3.14159265359
-
-vec3 texelCoordToVec(vec2 uv, int faceID)
-{
- mat3 faceUvVectors[6];
-/*
- // -x
- faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
- // +x
- faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
-
- // -y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
-
- // +y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
-
- // -z
- faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
-
- // +z
- faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
-*/
-
- // -x
- faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z
- faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face
-
- // +x
- faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z
- faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face
-
- // -y
- faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z
- faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face
-
- // +y
- faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z
- faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face
-
- // -z
- faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
- faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face
-
- // +z
- faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x
- faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
- faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face
-
- // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
- vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
- return normalize(result);
+vec3 texelCoordToVec(vec2 uv, int faceID) {
+ mat3 faceUvVectors[6];
+ /*
+ // -x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[3][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[2][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[5][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[4][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, 1.0); // +z face
+ */
+
+ // -x
+ faceUvVectors[0][0] = vec3(0.0, 0.0, 1.0); // u -> +z
+ faceUvVectors[0][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[0][2] = vec3(-1.0, 0.0, 0.0); // -x face
+
+ // +x
+ faceUvVectors[1][0] = vec3(0.0, 0.0, -1.0); // u -> -z
+ faceUvVectors[1][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[1][2] = vec3(1.0, 0.0, 0.0); // +x face
+
+ // -y
+ faceUvVectors[2][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[2][1] = vec3(0.0, 0.0, -1.0); // v -> -z
+ faceUvVectors[2][2] = vec3(0.0, -1.0, 0.0); // -y face
+
+ // +y
+ faceUvVectors[3][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[3][1] = vec3(0.0, 0.0, 1.0); // v -> +z
+ faceUvVectors[3][2] = vec3(0.0, 1.0, 0.0); // +y face
+
+ // -z
+ faceUvVectors[4][0] = vec3(-1.0, 0.0, 0.0); // u -> -x
+ faceUvVectors[4][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[4][2] = vec3(0.0, 0.0, -1.0); // -z face
+
+ // +z
+ faceUvVectors[5][0] = vec3(1.0, 0.0, 0.0); // u -> +x
+ faceUvVectors[5][1] = vec3(0.0, -1.0, 0.0); // v -> -y
+ faceUvVectors[5][2] = vec3(0.0, 0.0, 1.0); // +z face
+
+ // out = u * s_faceUv[0] + v * s_faceUv[1] + s_faceUv[2].
+ vec3 result = (faceUvVectors[faceID][0] * uv.x) + (faceUvVectors[faceID][1] * uv.y) + faceUvVectors[faceID][2];
+ return normalize(result);
}
-vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
-{
+vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N) {
float a = Roughness * Roughness; // DISNEY'S ROUGHNESS [see Burley'12 siggraph]
// Compute distribution direction
float Phi = 2.0 * M_PI * Xi.x;
- float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a*a - 1.0) * Xi.y));
+ float CosTheta = sqrt((1.0 - Xi.y) / (1.0 + (a * a - 1.0) * Xi.y));
float SinTheta = sqrt(1.0 - CosTheta * CosTheta);
// Convert to spherical direction
@@ -137,33 +134,29 @@ vec3 ImportanceSampleGGX(vec2 Xi, float Roughness, vec3 N)
}
// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float GGX(float NdotV, float a)
-{
+float GGX(float NdotV, float a) {
float k = a / 2.0;
return NdotV / (NdotV * (1.0 - k) + k);
}
// http://graphicrants.blogspot.com.au/2013/08/specular-brdf-reference.html
-float G_Smith(float a, float nDotV, float nDotL)
-{
+float G_Smith(float a, float nDotV, float nDotL) {
return GGX(nDotL, a * a) * GGX(nDotV, a * a);
}
float radicalInverse_VdC(uint bits) {
- bits = (bits << 16u) | (bits >> 16u);
- bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
- bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
- bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
- bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
- return float(bits) * 2.3283064365386963e-10; // / 0x100000000
+ bits = (bits << 16u) | (bits >> 16u);
+ bits = ((bits & 0x55555555u) << 1u) | ((bits & 0xAAAAAAAAu) >> 1u);
+ bits = ((bits & 0x33333333u) << 2u) | ((bits & 0xCCCCCCCCu) >> 2u);
+ bits = ((bits & 0x0F0F0F0Fu) << 4u) | ((bits & 0xF0F0F0F0u) >> 4u);
+ bits = ((bits & 0x00FF00FFu) << 8u) | ((bits & 0xFF00FF00u) >> 8u);
+ return float(bits) * 2.3283064365386963e-10; // / 0x100000000
}
vec2 Hammersley(uint i, uint N) {
- return vec2(float(i)/float(N), radicalInverse_VdC(i));
+ return vec2(float(i) / float(N), radicalInverse_VdC(i));
}
-
-
#ifdef LOW_QUALITY
#define SAMPLE_COUNT 64u
@@ -178,37 +171,33 @@ uniform bool z_flip;
#ifdef USE_SOURCE_PANORAMA
-vec4 texturePanorama(vec3 normal,sampler2D pano ) {
+vec4 texturePanorama(vec3 normal, sampler2D pano) {
vec2 st = vec2(
- atan(normal.x, normal.z),
- acos(normal.y)
- );
-
- if(st.x < 0.0)
- st.x += M_PI*2.0;
+ atan(normal.x, normal.z),
+ acos(normal.y));
- st/=vec2(M_PI*2.0,M_PI);
+ if (st.x < 0.0)
+ st.x += M_PI * 2.0;
- return textureLod(pano,st,0.0);
+ st /= vec2(M_PI * 2.0, M_PI);
+ return textureLod(pano, st, 0.0);
}
#endif
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
-
vec4 textureDualParaboloidArray(vec3 normal) {
vec3 norm = normalize(normal);
- norm.xy/=1.0+abs(norm.z);
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
- if (norm.z<0.0) {
- norm.y=0.5-norm.y+0.5;
+ norm.xy /= 1.0 + abs(norm.z);
+ norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25);
+ if (norm.z < 0.0) {
+ norm.y = 0.5 - norm.y + 0.5;
}
- return textureLod(source_dual_paraboloid_array, vec3(norm.xy, float(source_array_index) ), 0.0);
-
+ return textureLod(source_dual_paraboloid_array, vec3(norm.xy, float(source_array_index)), 0.0);
}
#endif
@@ -217,19 +206,18 @@ void main() {
#ifdef USE_DUAL_PARABOLOID
- vec3 N = vec3( uv_interp * 2.0 - 1.0, 0.0 );
- N.z = 0.5 - 0.5*((N.x * N.x) + (N.y * N.y));
+ vec3 N = vec3(uv_interp * 2.0 - 1.0, 0.0);
+ N.z = 0.5 - 0.5 * ((N.x * N.x) + (N.y * N.y));
N = normalize(N);
if (z_flip) {
- N.y=-N.y; //y is flipped to improve blending between both sides
- N.z=-N.z;
+ N.y = -N.y; //y is flipped to improve blending between both sides
+ N.z = -N.z;
}
-
#else
- vec2 uv = (uv_interp * 2.0) - 1.0;
- vec3 N = texelCoordToVec(uv, face_id);
+ vec2 uv = (uv_interp * 2.0) - 1.0;
+ vec3 N = texelCoordToVec(uv, face_id);
#endif
//vec4 color = color_interp;
@@ -237,49 +225,46 @@ void main() {
#ifdef USE_SOURCE_PANORAMA
- frag_color=vec4(texturePanorama(N,source_panorama).rgb,1.0);
+ frag_color = vec4(texturePanorama(N, source_panorama).rgb, 1.0);
#endif
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
- frag_color=vec4(textureDualParaboloidArray(N).rgb,1.0);
+ frag_color = vec4(textureDualParaboloidArray(N).rgb, 1.0);
#endif
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
- N.y=-N.y;
- frag_color=vec4(texture(N,source_cube).rgb,1.0);
+ N.y = -N.y;
+ frag_color = vec4(texture(N, source_cube).rgb, 1.0);
#endif
-
-
-
#else
vec4 sum = vec4(0.0, 0.0, 0.0, 0.0);
- for(uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) {
+ for (uint sampleNum = 0u; sampleNum < SAMPLE_COUNT; sampleNum++) {
vec2 xi = Hammersley(sampleNum, SAMPLE_COUNT);
- vec3 H = ImportanceSampleGGX( xi, roughness, N );
- vec3 V = N;
- vec3 L = normalize(2.0 * dot( V, H ) * H - V);
+ vec3 H = ImportanceSampleGGX(xi, roughness, N);
+ vec3 V = N;
+ vec3 L = (2.0 * dot(V, H) * H - V);
- float ndotl = clamp(dot(N, L),0.0,1.0);
+ float ndotl = clamp(dot(N, L), 0.0, 1.0);
- if (ndotl>0.0) {
+ if (ndotl > 0.0) {
#ifdef USE_SOURCE_PANORAMA
- sum.rgb += texturePanorama(H,source_panorama).rgb *ndotl;
+ sum.rgb += texturePanorama(L, source_panorama).rgb * ndotl;
#endif
#ifdef USE_SOURCE_DUAL_PARABOLOID_ARRAY
- sum.rgb += textureDualParaboloidArray(H).rgb *ndotl;
+ sum.rgb += textureDualParaboloidArray(L).rgb * ndotl;
#endif
#if !defined(USE_SOURCE_DUAL_PARABOLOID_ARRAY) && !defined(USE_SOURCE_PANORAMA)
- H.y=-H.y;
- sum.rgb += textureLod(source_cube, H, 0.0).rgb *ndotl;
+ L.y = -L.y;
+ sum.rgb += textureLod(source_cube, L, 0.0).rgb * ndotl;
#endif
sum.a += ndotl;
}
@@ -289,6 +274,4 @@ void main() {
frag_color = vec4(sum.rgb, 1.0);
#endif
-
}
-
diff --git a/drivers/gles3/shaders/effect_blur.glsl b/drivers/gles3/shaders/effect_blur.glsl
index c8567b4d53..b67d06bc10 100644
--- a/drivers/gles3/shaders/effect_blur.glsl
+++ b/drivers/gles3/shaders/effect_blur.glsl
@@ -1,8 +1,9 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
@@ -23,11 +24,13 @@ void main() {
#endif
}
+/* clang-format off */
[fragment]
#if !defined(GLES_OVER_GL)
precision mediump float;
#endif
+/* clang-format on */
in vec2 uv_interp;
uniform sampler2D source_color; //texunit:0
@@ -39,7 +42,6 @@ uniform sampler2D source_ssao; //texunit:1
uniform float lod;
uniform vec2 pixel_size;
-
layout(location = 0) out vec4 frag_color;
#ifdef SSAO_MERGE
@@ -48,31 +50,31 @@ uniform vec4 ssao_color;
#endif
-#if defined (GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL)
+#if defined(GLOW_GAUSSIAN_HORIZONTAL) || defined(GLOW_GAUSSIAN_VERTICAL)
uniform float glow_strength;
#endif
-#if defined(DOF_FAR_BLUR) || defined (DOF_NEAR_BLUR)
+#if defined(DOF_FAR_BLUR) || defined(DOF_NEAR_BLUR)
#ifdef DOF_QUALITY_LOW
-const int dof_kernel_size=5;
-const int dof_kernel_from=2;
-const float dof_kernel[5] = float[] (0.153388,0.221461,0.250301,0.221461,0.153388);
+const int dof_kernel_size = 5;
+const int dof_kernel_from = 2;
+const float dof_kernel[5] = float[](0.153388, 0.221461, 0.250301, 0.221461, 0.153388);
#endif
#ifdef DOF_QUALITY_MEDIUM
-const int dof_kernel_size=11;
-const int dof_kernel_from=5;
-const float dof_kernel[11] = float[] (0.055037,0.072806,0.090506,0.105726,0.116061,0.119726,0.116061,0.105726,0.090506,0.072806,0.055037);
+const int dof_kernel_size = 11;
+const int dof_kernel_from = 5;
+const float dof_kernel[11] = float[](0.055037, 0.072806, 0.090506, 0.105726, 0.116061, 0.119726, 0.116061, 0.105726, 0.090506, 0.072806, 0.055037);
#endif
#ifdef DOF_QUALITY_HIGH
-const int dof_kernel_size=21;
-const int dof_kernel_from=10;
-const float dof_kernel[21] = float[] (0.028174,0.032676,0.037311,0.041944,0.046421,0.050582,0.054261,0.057307,0.059587,0.060998,0.061476,0.060998,0.059587,0.057307,0.054261,0.050582,0.046421,0.041944,0.037311,0.032676,0.028174);
+const int dof_kernel_size = 21;
+const int dof_kernel_from = 10;
+const float dof_kernel[21] = float[](0.028174, 0.032676, 0.037311, 0.041944, 0.046421, 0.050582, 0.054261, 0.057307, 0.059587, 0.060998, 0.061476, 0.060998, 0.059587, 0.057307, 0.054261, 0.050582, 0.046421, 0.041944, 0.037311, 0.032676, 0.028174);
#endif
uniform sampler2D dof_source_depth; //texunit:1
@@ -88,7 +90,6 @@ uniform sampler2D source_dof_original; //texunit:2
#endif
-
#ifdef GLOW_FIRST_PASS
uniform float exposure;
@@ -112,53 +113,51 @@ uniform float camera_z_near;
void main() {
-
-
#ifdef GAUSSIAN_HORIZONTAL
vec2 pix_size = pixel_size;
- pix_size*=0.5; //reading from larger buffer, so use more samples
- vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.214607;
- color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.189879;
- color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.157305;
- color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.071303;
- color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.189879;
- color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.157305;
- color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.071303;
+ pix_size *= 0.5; //reading from larger buffer, so use more samples
+ vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.214607;
+ color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.189879;
+ color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.157305;
+ color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.071303;
+ color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.189879;
+ color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.157305;
+ color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.071303;
frag_color = color;
#endif
#ifdef GAUSSIAN_VERTICAL
- vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pixel_size,lod )*0.38774;
- color+=textureLod( source_color, uv_interp+vec2( 0.0, 1.0)*pixel_size,lod )*0.24477;
- color+=textureLod( source_color, uv_interp+vec2( 0.0, 2.0)*pixel_size,lod )*0.06136;
- color+=textureLod( source_color, uv_interp+vec2( 0.0,-1.0)*pixel_size,lod )*0.24477;
- color+=textureLod( source_color, uv_interp+vec2( 0.0,-2.0)*pixel_size,lod )*0.06136;
+ vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.38774;
+ color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.24477;
+ color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.06136;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.24477;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.06136;
frag_color = color;
#endif
-//glow uses larger sigma for a more rounded blur effect
+ //glow uses larger sigma for a more rounded blur effect
#ifdef GLOW_GAUSSIAN_HORIZONTAL
vec2 pix_size = pixel_size;
- pix_size*=0.5; //reading from larger buffer, so use more samples
- vec4 color =textureLod( source_color, uv_interp+vec2( 0.0, 0.0)*pix_size,lod )*0.174938;
- color+=textureLod( source_color, uv_interp+vec2( 1.0, 0.0)*pix_size,lod )*0.165569;
- color+=textureLod( source_color, uv_interp+vec2( 2.0, 0.0)*pix_size,lod )*0.140367;
- color+=textureLod( source_color, uv_interp+vec2( 3.0, 0.0)*pix_size,lod )*0.106595;
- color+=textureLod( source_color, uv_interp+vec2(-1.0, 0.0)*pix_size,lod )*0.165569;
- color+=textureLod( source_color, uv_interp+vec2(-2.0, 0.0)*pix_size,lod )*0.140367;
- color+=textureLod( source_color, uv_interp+vec2(-3.0, 0.0)*pix_size,lod )*0.106595;
- color*=glow_strength;
+ pix_size *= 0.5; //reading from larger buffer, so use more samples
+ vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pix_size, lod) * 0.174938;
+ color += textureLod(source_color, uv_interp + vec2(1.0, 0.0) * pix_size, lod) * 0.165569;
+ color += textureLod(source_color, uv_interp + vec2(2.0, 0.0) * pix_size, lod) * 0.140367;
+ color += textureLod(source_color, uv_interp + vec2(3.0, 0.0) * pix_size, lod) * 0.106595;
+ color += textureLod(source_color, uv_interp + vec2(-1.0, 0.0) * pix_size, lod) * 0.165569;
+ color += textureLod(source_color, uv_interp + vec2(-2.0, 0.0) * pix_size, lod) * 0.140367;
+ color += textureLod(source_color, uv_interp + vec2(-3.0, 0.0) * pix_size, lod) * 0.106595;
+ color *= glow_strength;
frag_color = color;
#endif
#ifdef GLOW_GAUSSIAN_VERTICAL
- vec4 color =textureLod( source_color, uv_interp+vec2(0.0, 0.0)*pixel_size,lod )*0.288713;
- color+=textureLod( source_color, uv_interp+vec2(0.0, 1.0)*pixel_size,lod )*0.233062;
- color+=textureLod( source_color, uv_interp+vec2(0.0, 2.0)*pixel_size,lod )*0.122581;
- color+=textureLod( source_color, uv_interp+vec2(0.0,-1.0)*pixel_size,lod )*0.233062;
- color+=textureLod( source_color, uv_interp+vec2(0.0,-2.0)*pixel_size,lod )*0.122581;
- color*=glow_strength;
+ vec4 color = textureLod(source_color, uv_interp + vec2(0.0, 0.0) * pixel_size, lod) * 0.288713;
+ color += textureLod(source_color, uv_interp + vec2(0.0, 1.0) * pixel_size, lod) * 0.233062;
+ color += textureLod(source_color, uv_interp + vec2(0.0, 2.0) * pixel_size, lod) * 0.122581;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -1.0) * pixel_size, lod) * 0.233062;
+ color += textureLod(source_color, uv_interp + vec2(0.0, -2.0) * pixel_size, lod) * 0.122581;
+ color *= glow_strength;
frag_color = color;
#endif
@@ -166,47 +165,45 @@ void main() {
vec4 color_accum = vec4(0.0);
- float depth = textureLod( dof_source_depth, uv_interp, 0.0).r;
+ float depth = textureLod(dof_source_depth, uv_interp, 0.0).r;
depth = depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif
- float amount = smoothstep(dof_begin,dof_end,depth);
- float k_accum=0.0;
+ float amount = smoothstep(dof_begin, dof_end, depth);
+ float k_accum = 0.0;
- for(int i=0;i<dof_kernel_size;i++) {
+ for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i-dof_kernel_from;
+ int int_ofs = i - dof_kernel_from;
vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * amount * dof_radius;
float tap_k = dof_kernel[i];
- float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r;
+ float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- tap_depth = ((tap_depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
#endif
- float tap_amount = mix(smoothstep(dof_begin,dof_end,tap_depth),1.0,int_ofs==0);
- tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect
-
- vec4 tap_color = textureLod( source_color, tap_uv, 0.0) * tap_k;
-
- k_accum+=tap_k*tap_amount;
- color_accum+=tap_color*tap_amount;
+ float tap_amount = mix(smoothstep(dof_begin, dof_end, tap_depth), 1.0, int_ofs == 0);
+ tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
+ vec4 tap_color = textureLod(source_color, tap_uv, 0.0) * tap_k;
+ k_accum += tap_k * tap_amount;
+ color_accum += tap_color * tap_amount;
}
- if (k_accum>0.0) {
- color_accum/=k_accum;
+ if (k_accum > 0.0) {
+ color_accum /= k_accum;
}
- frag_color = color_accum;///k_accum;
+ frag_color = color_accum; ///k_accum;
#endif
@@ -214,47 +211,45 @@ void main() {
vec4 color_accum = vec4(0.0);
- float max_accum=0.0;
+ float max_accum = 0.0;
- for(int i=0;i<dof_kernel_size;i++) {
+ for (int i = 0; i < dof_kernel_size; i++) {
- int int_ofs = i-dof_kernel_from;
+ int int_ofs = i - dof_kernel_from;
vec2 tap_uv = uv_interp + dof_dir * float(int_ofs) * dof_radius;
- float ofs_influence = max(0.0,1.0-float(abs(int_ofs))/float(dof_kernel_from));
+ float ofs_influence = max(0.0, 1.0 - float(abs(int_ofs)) / float(dof_kernel_from));
float tap_k = dof_kernel[i];
- vec4 tap_color = textureLod( source_color, tap_uv, 0.0);
+ vec4 tap_color = textureLod(source_color, tap_uv, 0.0);
- float tap_depth = texture( dof_source_depth, tap_uv, 0.0).r;
+ float tap_depth = texture(dof_source_depth, tap_uv, 0.0).r;
tap_depth = tap_depth * 2.0 - 1.0;
-#ifdef USE_ORTHOGONAL_PROJECTION
- tap_depth = ((tap_depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+#ifdef USE_ORTHOGONAL_PROJECTION
+ tap_depth = ((tap_depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
tap_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - tap_depth * (camera_z_far - camera_z_near));
#endif
- float tap_amount = 1.0-smoothstep(dof_end,dof_begin,tap_depth);
- tap_amount*=tap_amount*tap_amount; //prevent undesired glow effect
+ float tap_amount = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
+ tap_amount *= tap_amount * tap_amount; //prevent undesired glow effect
#ifdef DOF_NEAR_FIRST_TAP
- tap_color.a= 1.0-smoothstep(dof_end,dof_begin,tap_depth);
+ tap_color.a = 1.0 - smoothstep(dof_end, dof_begin, tap_depth);
#endif
- max_accum=max(max_accum,tap_amount*ofs_influence);
-
- color_accum+=tap_color*tap_k;
+ max_accum = max(max_accum, tap_amount * ofs_influence);
+ color_accum += tap_color * tap_k;
}
- color_accum.a=max(color_accum.a,sqrt(max_accum));
-
+ color_accum.a = max(color_accum.a, sqrt(max_accum));
#ifdef DOF_NEAR_BLUR_MERGE
- vec4 original = textureLod( source_dof_original, uv_interp, 0.0);
- color_accum = mix(original,color_accum,color_accum.a);
+ vec4 original = textureLod(source_dof_original, uv_interp, 0.0);
+ color_accum = mix(original, color_accum, color_accum.a);
#endif
@@ -265,37 +260,32 @@ void main() {
#endif
-
-
#ifdef GLOW_FIRST_PASS
#ifdef GLOW_USE_AUTO_EXPOSURE
- frag_color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey;
+ frag_color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / auto_exposure_grey;
#endif
- frag_color*=exposure;
+ frag_color *= exposure;
- 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 );
+ 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;
#endif
-
#ifdef SIMPLE_COPY
- vec4 color =textureLod( source_color, uv_interp,0.0);
+ vec4 color = textureLod(source_color, uv_interp, 0.0);
frag_color = color;
#endif
#ifdef SSAO_MERGE
- vec4 color =textureLod( source_color, uv_interp,0.0);
- float ssao =textureLod( source_ssao, uv_interp,0.0).r;
+ vec4 color = textureLod(source_color, uv_interp, 0.0);
+ float ssao = textureLod(source_ssao, uv_interp, 0.0).r;
- frag_color = vec4( mix(color.rgb,color.rgb*mix(ssao_color.rgb,vec3(1.0),ssao),color.a), 1.0 );
+ frag_color = vec4(mix(color.rgb, color.rgb * mix(ssao_color.rgb, vec3(1.0), ssao), color.a), 1.0);
#endif
-
-
}
diff --git a/drivers/gles3/shaders/exposure.glsl b/drivers/gles3/shaders/exposure.glsl
index 001b90a0f1..759adcda06 100644
--- a/drivers/gles3/shaders/exposure.glsl
+++ b/drivers/gles3/shaders/exposure.glsl
@@ -1,19 +1,19 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
void main() {
gl_Position = vertex_attrib;
-
}
+/* clang-format off */
[fragment]
-
uniform highp sampler2D source_exposure; //texunit:0
+/* clang-format on */
#ifdef EXPOSURE_BEGIN
@@ -33,66 +33,56 @@ uniform highp float max_luminance;
layout(location = 0) out highp float exposure;
-
-
void main() {
-
-
#ifdef EXPOSURE_BEGIN
-
- ivec2 src_pos = ivec2(gl_FragCoord.xy)*source_render_size/target_size;
+ ivec2 src_pos = ivec2(gl_FragCoord.xy) * source_render_size / target_size;
#if 1
//more precise and expensive, but less jittery
- ivec2 next_pos = ivec2(gl_FragCoord.xy+ivec2(1))*source_render_size/target_size;
- next_pos = max(next_pos,src_pos+ivec2(1)); //so it at least reads one pixel
- highp vec3 source_color=vec3(0.0);
- for(int i=src_pos.x;i<next_pos.x;i++) {
- for(int j=src_pos.y;j<next_pos.y;j++) {
- source_color += texelFetch(source_exposure,ivec2(i,j),0).rgb;
+ ivec2 next_pos = ivec2(gl_FragCoord.xy + ivec2(1)) * source_render_size / target_size;
+ next_pos = max(next_pos, src_pos + ivec2(1)); //so it at least reads one pixel
+ highp vec3 source_color = vec3(0.0);
+ for (int i = src_pos.x; i < next_pos.x; i++) {
+ for (int j = src_pos.y; j < next_pos.y; j++) {
+ source_color += texelFetch(source_exposure, ivec2(i, j), 0).rgb;
}
}
- source_color/=float( (next_pos.x-src_pos.x)*(next_pos.y-src_pos.y) );
+ source_color /= float((next_pos.x - src_pos.x) * (next_pos.y - src_pos.y));
#else
- highp vec3 source_color = texelFetch(source_exposure,src_pos,0).rgb;
+ highp vec3 source_color = texelFetch(source_exposure, src_pos, 0).rgb;
#endif
- exposure = max(source_color.r,max(source_color.g,source_color.b));
+ exposure = max(source_color.r, max(source_color.g, source_color.b));
#else
ivec2 coord = ivec2(gl_FragCoord.xy);
- exposure = texelFetch(source_exposure,coord*3+ivec2(0,0),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(1,0),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(2,0),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(0,1),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(1,1),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(2,1),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(0,2),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(1,2),0).r;
- exposure += texelFetch(source_exposure,coord*3+ivec2(2,2),0).r;
- exposure *= (1.0/9.0);
+ exposure = texelFetch(source_exposure, coord * 3 + ivec2(0, 0), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 0), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 0), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(0, 1), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 1), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 1), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(0, 2), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(1, 2), 0).r;
+ exposure += texelFetch(source_exposure, coord * 3 + ivec2(2, 2), 0).r;
+ exposure *= (1.0 / 9.0);
#ifdef EXPOSURE_END
#ifdef EXPOSURE_FORCE_SET
//will stay as is
#else
- highp float prev_lum = texelFetch(prev_exposure,ivec2(0,0),0).r; //1 pixel previous exposure
- exposure = clamp( prev_lum + (exposure-prev_lum)*exposure_adjust,min_luminance,max_luminance);
+ highp float prev_lum = texelFetch(prev_exposure, ivec2(0, 0), 0).r; //1 pixel previous exposure
+ exposure = clamp(prev_lum + (exposure - prev_lum) * exposure_adjust, min_luminance, max_luminance);
#endif //EXPOSURE_FORCE_SET
-
#endif //EXPOSURE_END
#endif //EXPOSURE_BEGIN
-
-
}
-
-
diff --git a/drivers/gles3/shaders/particles.glsl b/drivers/gles3/shaders/particles.glsl
index fbee08c0fe..8523c08597 100644
--- a/drivers/gles3/shaders/particles.glsl
+++ b/drivers/gles3/shaders/particles.glsl
@@ -1,14 +1,13 @@
+/* clang-format off */
[vertex]
-
-
-layout(location=0) in highp vec4 color;
-layout(location=1) in highp vec4 velocity_active;
-layout(location=2) in highp vec4 custom;
-layout(location=3) in highp vec4 xform_1;
-layout(location=4) in highp vec4 xform_2;
-layout(location=5) in highp vec4 xform_3;
-
+layout(location = 0) in highp vec4 color;
+/* clang-format on */
+layout(location = 1) in highp vec4 velocity_active;
+layout(location = 2) in highp vec4 custom;
+layout(location = 3) in highp vec4 xform_1;
+layout(location = 4) in highp vec4 xform_2;
+layout(location = 5) in highp vec4 xform_3;
struct Attractor {
@@ -39,7 +38,6 @@ uniform float lifetime;
uniform mat4 emission_transform;
uniform uint random_seed;
-
out highp vec4 out_color; //tfb:
out highp vec4 out_velocity_active; //tfb:
out highp vec4 out_custom; //tfb:
@@ -47,20 +45,24 @@ out highp vec4 out_xform_1; //tfb:
out highp vec4 out_xform_2; //tfb:
out highp vec4 out_xform_3; //tfb:
-
#if defined(USE_MATERIAL)
+/* clang-format off */
layout(std140) uniform UniformData { //ubo:0
MATERIAL_UNIFORMS
};
+/* clang-format on */
#endif
+/* clang-format off */
VERTEX_SHADER_GLOBALS
+/* clang-format on */
+
uint hash(uint x) {
x = ((x >> uint(16)) ^ x) * uint(0x45d9f3b);
@@ -69,13 +71,12 @@ uint hash(uint x) {
return x;
}
-
void main() {
#ifdef PARTICLES_COPY
- out_color=color;
- out_velocity_active=velocity_active;
+ out_color = color;
+ out_velocity_active = velocity_active;
out_custom = custom;
out_xform_1 = xform_1;
out_xform_2 = xform_2;
@@ -83,47 +84,47 @@ void main() {
#else
- bool apply_forces=true;
- bool apply_velocity=true;
- float local_delta=delta;
+ bool apply_forces = true;
+ bool apply_velocity = true;
+ float local_delta = delta;
float mass = 1.0;
- float restart_phase = float(gl_VertexID)/float(total_particles);
+ float restart_phase = float(gl_VertexID) / float(total_particles);
- if (randomness>0.0) {
+ if (randomness > 0.0) {
uint seed = cycle;
if (restart_phase >= system_phase) {
- seed-=uint(1);
+ seed -= uint(1);
}
- seed*=uint(total_particles);
- seed+=uint(gl_VertexID);
+ seed *= uint(total_particles);
+ seed += uint(gl_VertexID);
float random = float(hash(seed) % uint(65536)) / 65536.0;
- restart_phase+=randomness * random * 1.0 / float(total_particles);
+ restart_phase += randomness * random * 1.0 / float(total_particles);
}
- restart_phase*= (1.0-explosiveness);
- bool restart=false;
+ restart_phase *= (1.0 - explosiveness);
+ bool restart = false;
bool shader_active = velocity_active.a > 0.5;
if (system_phase > prev_system_phase) {
// restart_phase >= prev_system_phase is used so particles emit in the first frame they are processed
- if (restart_phase >= prev_system_phase && restart_phase < system_phase ) {
- restart=true;
+ if (restart_phase >= prev_system_phase && restart_phase < system_phase) {
+ restart = true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (system_phase - restart_phase) * lifetime;
#endif
}
- } else if(delta > 0.0) {
+ } else if (delta > 0.0) {
if (restart_phase >= prev_system_phase) {
- restart=true;
+ restart = true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (1.0 - restart_phase + system_phase) * lifetime;
#endif
- } else if (restart_phase < system_phase ) {
- restart=true;
+ } else if (restart_phase < system_phase) {
+ restart = true;
#ifdef USE_FRACTIONAL_DELTA
local_delta = (system_phase - restart_phase) * lifetime;
#endif
@@ -133,14 +134,14 @@ void main() {
uint current_cycle = cycle;
if (system_phase < restart_phase) {
- current_cycle-=uint(1);
+ current_cycle -= uint(1);
}
uint particle_number = current_cycle * uint(total_particles) + uint(gl_VertexID);
int index = int(gl_VertexID);
if (restart) {
- shader_active=emitting;
+ shader_active = emitting;
}
mat4 xform;
@@ -150,30 +151,33 @@ void main() {
#else
if (clear || restart) {
#endif
- out_color=vec4(1.0);
- out_velocity_active=vec4(0.0);
- out_custom=vec4(0.0);
+ out_color = vec4(1.0);
+ out_velocity_active = vec4(0.0);
+ out_custom = vec4(0.0);
if (!restart)
- shader_active=false;
+ shader_active = false;
xform = mat4(
- vec4(1.0,0.0,0.0,0.0),
- vec4(0.0,1.0,0.0,0.0),
- vec4(0.0,0.0,1.0,0.0),
- vec4(0.0,0.0,0.0,1.0)
- );
+ vec4(1.0, 0.0, 0.0, 0.0),
+ vec4(0.0, 1.0, 0.0, 0.0),
+ vec4(0.0, 0.0, 1.0, 0.0),
+ vec4(0.0, 0.0, 0.0, 1.0));
} else {
- out_color=color;
- out_velocity_active=velocity_active;
- out_custom=custom;
- xform = transpose(mat4(xform_1,xform_2,xform_3,vec4(vec3(0.0),1.0)));
+ out_color = color;
+ out_velocity_active = velocity_active;
+ out_custom = custom;
+ xform = transpose(mat4(xform_1, xform_2, xform_3, vec4(vec3(0.0), 1.0)));
}
if (shader_active) {
//execute shader
{
+ /* clang-format off */
+
VERTEX_SHADER_CODE
+
+ /* clang-format on */
}
#if !defined(DISABLE_FORCE)
@@ -181,26 +185,25 @@ VERTEX_SHADER_CODE
if (false) {
vec3 force = vec3(0.0);
- for(int i=0;i<attractor_count;i++) {
+ for (int i = 0; i < attractor_count; i++) {
vec3 rel_vec = xform[3].xyz - attractors[i].pos;
float dist = length(rel_vec);
if (attractors[i].radius < dist)
continue;
- if (attractors[i].eat_radius>0.0 && attractors[i].eat_radius > dist) {
- out_velocity_active.a=0.0;
+ if (attractors[i].eat_radius > 0.0 && attractors[i].eat_radius > dist) {
+ out_velocity_active.a = 0.0;
}
rel_vec = normalize(rel_vec);
- float attenuation = pow(dist / attractors[i].radius,attractors[i].attenuation);
+ float attenuation = pow(dist / attractors[i].radius, attractors[i].attenuation);
- if (attractors[i].dir==vec3(0.0)) {
+ if (attractors[i].dir == vec3(0.0)) {
//towards center
- force+=attractors[i].strength * rel_vec * attenuation * mass;
+ force += attractors[i].strength * rel_vec * attenuation * mass;
} else {
- force+=attractors[i].strength * attractors[i].dir * attenuation *mass;
-
+ force += attractors[i].strength * attractors[i].dir * attenuation * mass;
}
}
@@ -216,25 +219,24 @@ VERTEX_SHADER_CODE
}
#endif
} else {
- xform=mat4(0.0);
+ xform = mat4(0.0);
}
xform = transpose(xform);
- out_velocity_active.a = mix(0.0,1.0,shader_active);
+ out_velocity_active.a = mix(0.0, 1.0, shader_active);
out_xform_1 = xform[0];
out_xform_2 = xform[1];
out_xform_3 = xform[2];
#endif //PARTICLES_COPY
-
}
+/* clang-format off */
[fragment]
-//any code here is never executed, stuff is filled just so it works
-
+// any code here is never executed, stuff is filled just so it works
#if defined(USE_MATERIAL)
@@ -251,10 +253,15 @@ FRAGMENT_SHADER_GLOBALS
void main() {
{
+
LIGHT_SHADER_CODE
+
}
{
+
FRAGMENT_SHADER_CODE
+
}
}
+/* clang-format on */
diff --git a/drivers/gles3/shaders/resolve.glsl b/drivers/gles3/shaders/resolve.glsl
index 0b50a9c57b..d64d8308c1 100644
--- a/drivers/gles3/shaders/resolve.glsl
+++ b/drivers/gles3/shaders/resolve.glsl
@@ -1,27 +1,29 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
-
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
}
+/* clang-format off */
[fragment]
#if !defined(GLES_OVER_GL)
precision mediump float;
#endif
+/* clang-format on */
in vec2 uv_interp;
-uniform sampler2D source_specular; //texunit:0
-uniform sampler2D source_ssr; //texunit:1
+uniform sampler2D source_specular; // texunit:0
+uniform sampler2D source_ssr; // texunit:1
uniform vec2 pixel_size;
@@ -31,14 +33,12 @@ layout(location = 0) out vec4 frag_color;
void main() {
- vec4 specular = texture( source_specular, uv_interp );
+ vec4 specular = texture(source_specular, uv_interp);
#ifdef USE_SSR
-
- vec4 ssr = textureLod(source_ssr,uv_interp,0.0);
- specular.rgb = mix(specular.rgb,ssr.rgb*specular.a,ssr.a);
+ vec4 ssr = textureLod(source_ssr, uv_interp, 0.0);
+ specular.rgb = mix(specular.rgb, ssr.rgb * specular.a, ssr.a);
#endif
- frag_color = vec4(specular.rgb,1.0);
+ frag_color = vec4(specular.rgb, 1.0);
}
-
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index f5481c597c..12cbe02d0c 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -1,3 +1,4 @@
+/* clang-format off */
[vertex]
#define M_PI 3.14159265359
@@ -16,50 +17,50 @@ ARRAY_WEIGHTS=7,
ARRAY_INDEX=8,
*/
-//hack to use uv if no uv present so it works with lightmap
-
+// hack to use uv if no uv present so it works with lightmap
/* INPUT ATTRIBS */
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=1) in vec3 normal_attrib;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 1) in vec3 normal_attrib;
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
-layout(location=2) in vec4 tangent_attrib;
+layout(location = 2) in vec4 tangent_attrib;
#endif
#if defined(ENABLE_COLOR_INTERP)
-layout(location=3) in vec4 color_attrib;
+layout(location = 3) in vec4 color_attrib;
#endif
#if defined(ENABLE_UV_INTERP)
-layout(location=4) in vec2 uv_attrib;
+layout(location = 4) in vec2 uv_attrib;
#endif
#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
-layout(location=5) in vec2 uv2_attrib;
+layout(location = 5) in vec2 uv2_attrib;
#endif
uniform float normal_mult;
#ifdef USE_SKELETON
-layout(location=6) in uvec4 bone_indices; // attrib:6
-layout(location=7) in vec4 bone_weights; // attrib:7
+layout(location = 6) in uvec4 bone_indices; // attrib:6
+layout(location = 7) in vec4 bone_weights; // attrib:7
#endif
#ifdef USE_INSTANCING
-layout(location=8) in highp vec4 instance_xform0;
-layout(location=9) in highp vec4 instance_xform1;
-layout(location=10) in highp vec4 instance_xform2;
-layout(location=11) in lowp vec4 instance_color;
+layout(location = 8) in highp vec4 instance_xform0;
+layout(location = 9) in highp vec4 instance_xform1;
+layout(location = 10) in highp vec4 instance_xform2;
+layout(location = 11) in lowp vec4 instance_color;
#if defined(ENABLE_INSTANCE_CUSTOM)
-layout(location=12) in highp vec4 instance_custom_data;
+layout(location = 12) in highp vec4 instance_custom_data;
#endif
#endif
-layout(std140) uniform SceneData { //ubo:0
+layout(std140) uniform SceneData { // ubo:0
highp mat4 projection_matrix;
highp mat4 inv_projection_matrix;
@@ -90,6 +91,8 @@ layout(std140) uniform SceneData { //ubo:0
mediump float reflection_multiplier;
mediump float subsurface_scatter_width;
mediump float ambient_occlusion_affect_light;
+ mediump float ambient_occlusion_affect_ao_channel;
+ mediump float opaque_prepass_threshold;
bool fog_depth_enabled;
highp float fog_depth_begin;
@@ -100,12 +103,10 @@ layout(std140) uniform SceneData { //ubo:0
highp float fog_height_min;
highp float fog_height_max;
highp float fog_height_curve;
-
};
uniform highp mat4 world_transform;
-
#ifdef USE_LIGHT_DIRECTIONAL
layout(std140) uniform DirectionalLightData { //ubo:3
@@ -113,7 +114,7 @@ layout(std140) uniform DirectionalLightData { //ubo:3
highp vec4 light_pos_inv_radius;
mediump vec4 light_direction_attenuation;
mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
+ mediump vec4 light_params; // cone attenuation, angle, specular, shadow enabled,
mediump vec4 light_clamp;
mediump vec4 shadow_color_contact;
highp mat4 shadow_matrix1;
@@ -133,14 +134,12 @@ struct LightData {
highp vec4 light_pos_inv_radius;
mediump vec4 light_direction_attenuation;
mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
+ mediump vec4 light_params; // cone attenuation, angle, specular, shadow enabled,
mediump vec4 light_clamp;
mediump vec4 shadow_color_contact;
highp mat4 shadow_matrix;
-
};
-
layout(std140) uniform OmniLightData { //ubo:4
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
@@ -153,7 +152,6 @@ layout(std140) uniform SpotLightData { //ubo:5
#ifdef USE_FORWARD_LIGHTING
-
uniform int omni_light_indices[MAX_FORWARD_LIGHTS];
uniform int omni_light_count;
@@ -165,49 +163,45 @@ uniform int spot_light_count;
out vec4 diffuse_light_interp;
out vec4 specular_light_interp;
-void light_compute(vec3 N, vec3 L,vec3 V, vec3 light_color, float roughness, inout vec3 diffuse, inout vec3 specular) {
+void light_compute(vec3 N, vec3 L, vec3 V, vec3 light_color, float roughness, inout vec3 diffuse, inout vec3 specular) {
- float dotNL = max(dot(N,L), 0.0 );
+ float dotNL = max(dot(N, L), 0.0);
diffuse += dotNL * light_color / M_PI;
if (roughness > 0.0) {
vec3 H = normalize(V + L);
- float dotNH = max(dot(N,H), 0.0 );
- float intensity = (roughness >= 1.0 ? 1.0 : pow( dotNH, (1.0-roughness) * 256.0));
+ float dotNH = max(dot(N, H), 0.0);
+ float intensity = (roughness >= 1.0 ? 1.0 : pow(dotNH, (1.0 - roughness) * 256.0));
specular += light_color * intensity;
-
}
}
-void light_process_omni(int idx, vec3 vertex, vec3 eye_vec,vec3 normal, float roughness,inout vec3 diffuse, inout vec3 specular) {
+void light_process_omni(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, inout vec3 diffuse, inout vec3 specular) {
- vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz-vertex;
- float light_length = length( light_rel_vec );
- float normalized_distance = light_length*omni_lights[idx].light_pos_inv_radius.w;
- vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w ));
-
- light_compute(normal,normalize(light_rel_vec),eye_vec,omni_lights[idx].light_color_energy.rgb * light_attenuation,roughness,diffuse,specular);
+ vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex;
+ float light_length = length(light_rel_vec);
+ float normalized_distance = light_length * omni_lights[idx].light_pos_inv_radius.w;
+ vec3 light_attenuation = vec3(pow(max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w));
+ light_compute(normal, normalize(light_rel_vec), eye_vec, omni_lights[idx].light_color_energy.rgb * light_attenuation, roughness, diffuse, specular);
}
void light_process_spot(int idx, vec3 vertex, vec3 eye_vec, vec3 normal, float roughness, inout vec3 diffuse, inout vec3 specular) {
- vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz-vertex;
- float light_length = length( light_rel_vec );
- float normalized_distance = light_length*spot_lights[idx].light_pos_inv_radius.w;
- vec3 light_attenuation = vec3(pow( max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w ));
+ vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex;
+ float light_length = length(light_rel_vec);
+ float normalized_distance = light_length * spot_lights[idx].light_pos_inv_radius.w;
+ vec3 light_attenuation = vec3(pow(max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w));
vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz;
- float spot_cutoff=spot_lights[idx].light_params.y;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff);
+ float spot_cutoff = spot_lights[idx].light_params.y;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff);
float spot_rim = (1.0 - scos) / (1.0 - spot_cutoff);
- light_attenuation *= 1.0 - pow( max(spot_rim,0.001), spot_lights[idx].light_params.x);
-
+ light_attenuation *= 1.0 - pow(max(spot_rim, 0.001), spot_lights[idx].light_params.x);
- light_compute(normal,normalize(light_rel_vec),eye_vec,spot_lights[idx].light_color_energy.rgb*light_attenuation,roughness,diffuse,specular);
+ light_compute(normal, normalize(light_rel_vec), eye_vec, spot_lights[idx].light_color_energy.rgb * light_attenuation, roughness, diffuse, specular);
}
-
#endif
/* Varyings */
@@ -223,29 +217,33 @@ out vec4 color_interp;
out vec2 uv_interp;
#endif
-#if defined(ENABLE_UV2_INTERP) || defined (USE_LIGHTMAP)
+#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
out vec2 uv2_interp;
#endif
-
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
out vec3 tangent_interp;
out vec3 binormal_interp;
#endif
-
#if defined(USE_MATERIAL)
-layout(std140) uniform UniformData { //ubo:1
+/* clang-format off */
+layout(std140) uniform UniformData { // ubo:1
MATERIAL_UNIFORMS
};
+/* clang-format on */
#endif
+/* clang-format off */
+
VERTEX_SHADER_GLOBALS
+/* clang-format on */
+
#ifdef RENDER_DEPTH_DUAL_PARABOLOID
out highp float dp_clip;
@@ -255,7 +253,7 @@ out highp float dp_clip;
#define SKELETON_TEXTURE_WIDTH 256
#ifdef USE_SKELETON
-uniform highp sampler2D skeleton_texture; //texunit:-1
+uniform highp sampler2D skeleton_texture; // texunit:-1
#endif
out highp vec4 position_interp;
@@ -270,21 +268,19 @@ void main() {
mat4 world_matrix = world_transform;
-
#ifdef USE_INSTANCING
{
- highp mat4 m=mat4(instance_xform0,instance_xform1,instance_xform2,vec4(0.0,0.0,0.0,1.0));
+ highp mat4 m = mat4(instance_xform0, instance_xform1, instance_xform2, vec4(0.0, 0.0, 0.0, 1.0));
world_matrix = world_matrix * transpose(m);
}
#endif
vec3 normal = normal_attrib * normal_mult;
-
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
vec3 tangent = tangent_attrib.xyz;
- tangent*=normal_mult;
+ tangent *= normal_mult;
float binormalf = tangent_attrib.a;
#endif
@@ -296,10 +292,9 @@ void main() {
#endif
-
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- vec3 binormal = normalize( cross(normal,tangent) * binormalf );
+ vec3 binormal = normalize(cross(normal, tangent) * binormalf);
#endif
#if defined(ENABLE_UV_INTERP)
@@ -322,84 +317,95 @@ void main() {
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
vertex = world_matrix * vertex;
- normal = normalize((world_matrix * vec4(normal,0.0)).xyz);
+
+#if defined(ENSURE_CORRECT_NORMALS)
+ mat3 normal_matrix = mat3(transpose(inverse(world_matrix)));
+ normal = normal_matrix * normal;
+#else
+ normal = normalize((world_matrix * vec4(normal, 0.0)).xyz);
+#endif
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- tangent = normalize((world_matrix * vec4(tangent,0.0)).xyz);
- binormal = normalize((world_matrix * vec4(binormal,0.0)).xyz);
+ tangent = normalize((world_matrix * vec4(tangent, 0.0)).xyz);
+ binormal = normalize((world_matrix * vec4(binormal, 0.0)).xyz);
#endif
#endif
- float roughness=0.0;
+ float roughness = 1.0;
//defines that make writing custom shaders easier
#define projection_matrix local_projection
#define world_transform world_matrix
-
#ifdef USE_SKELETON
{
//skeleton transform
ivec4 bone_indicesi = ivec4(bone_indices); // cast to signed int
- ivec2 tex_ofs = ivec2( bone_indicesi.x%256, (bone_indicesi.x/256)*3 );
- highp mat3x4 m = mat3x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
- ) * bone_weights.x;
+ ivec2 tex_ofs = ivec2(bone_indicesi.x % 256, (bone_indicesi.x / 256) * 3);
+ highp mat3x4 m;
+ m = mat3x4(
+ texelFetch(skeleton_texture, tex_ofs, 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) *
+ bone_weights.x;
- tex_ofs = ivec2( bone_indicesi.y%256, (bone_indicesi.y/256)*3 );
+ tex_ofs = ivec2(bone_indicesi.y % 256, (bone_indicesi.y / 256) * 3);
- m+= mat3x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
- ) * bone_weights.y;
+ m += mat3x4(
+ texelFetch(skeleton_texture, tex_ofs, 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) *
+ bone_weights.y;
- tex_ofs = ivec2( bone_indicesi.z%256, (bone_indicesi.z/256)*3 );
+ tex_ofs = ivec2(bone_indicesi.z % 256, (bone_indicesi.z / 256) * 3);
- m+= mat3x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
- ) * bone_weights.z;
+ m += mat3x4(
+ texelFetch(skeleton_texture, tex_ofs, 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) *
+ bone_weights.z;
+ tex_ofs = ivec2(bone_indicesi.w % 256, (bone_indicesi.w / 256) * 3);
- tex_ofs = ivec2( bone_indicesi.w%256, (bone_indicesi.w/256)*3 );
+ m += mat3x4(
+ texelFetch(skeleton_texture, tex_ofs, 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 1), 0),
+ texelFetch(skeleton_texture, tex_ofs + ivec2(0, 2), 0)) *
+ bone_weights.w;
- m+= mat3x4(
- texelFetch(skeleton_texture,tex_ofs,0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,1),0),
- texelFetch(skeleton_texture,tex_ofs+ivec2(0,2),0)
- ) * bone_weights.w;
-
- mat4 bone_matrix = transpose(mat4(m[0],m[1],m[2],vec4(0.0,0.0,0.0,1.0)));
+ mat4 bone_matrix = transpose(mat4(m[0], m[1], m[2], vec4(0.0, 0.0, 0.0, 1.0)));
world_matrix = bone_matrix * world_matrix;
}
#endif
mat4 modelview = camera_inverse_matrix * world_matrix;
-{
+ {
+ /* clang-format off */
VERTEX_SHADER_CODE
-}
-
-
+ /* clang-format on */
+ }
-//using local coordinates (default)
+// using local coordinates (default)
#if !defined(SKIP_TRANSFORM_USED) && !defined(VERTEX_WORLD_COORDS_USED)
vertex = modelview * vertex;
- normal = normalize((modelview * vec4(normal,0.0)).xyz);
+
+#if defined(ENSURE_CORRECT_NORMALS)
+ mat3 normal_matrix = mat3(transpose(inverse(modelview)));
+ normal = normal_matrix * normal;
+#else
+ normal = normalize((modelview * vec4(normal, 0.0)).xyz);
+#endif
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- tangent = normalize((modelview * vec4(tangent,0.0)).xyz);
- binormal = normalize((modelview * vec4(binormal,0.0)).xyz);
+ tangent = normalize((modelview * vec4(tangent, 0.0)).xyz);
+ binormal = normalize((modelview * vec4(binormal, 0.0)).xyz);
#endif
#endif
@@ -407,74 +413,70 @@ VERTEX_SHADER_CODE
#if !defined(SKIP_TRANSFORM_USED) && defined(VERTEX_WORLD_COORDS_USED)
vertex = camera_inverse_matrix * vertex;
- normal = normalize((camera_inverse_matrix * vec4(normal,0.0)).xyz);
+ normal = normalize((camera_inverse_matrix * vec4(normal, 0.0)).xyz);
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
- tangent = normalize((camera_inverse_matrix * vec4(tangent,0.0)).xyz);
- binormal = normalize((camera_inverse_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
vertex_interp = vertex.xyz;
normal_interp = normal;
-
#if defined(ENABLE_TANGENT_INTERP) || defined(ENABLE_NORMALMAP) || defined(LIGHT_USE_ANISOTROPY)
tangent_interp = tangent;
binormal_interp = binormal;
#endif
-
#ifdef RENDER_DEPTH
-
#ifdef RENDER_DEPTH_DUAL_PARABOLOID
- vertex_interp.z*= shadow_dual_paraboloid_render_side;
- normal_interp.z*= shadow_dual_paraboloid_render_side;
+ vertex_interp.z *= shadow_dual_paraboloid_render_side;
+ normal_interp.z *= shadow_dual_paraboloid_render_side;
- dp_clip=vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
+ dp_clip = vertex_interp.z; //this attempts to avoid noise caused by objects sent to the other parabolloid side due to bias
//for dual paraboloid shadow mapping, this is the fastest but least correct way, as it curves straight edges
- highp vec3 vtx = vertex_interp+normalize(vertex_interp)*z_offset;
+ highp vec3 vtx = vertex_interp + normalize(vertex_interp) * z_offset;
highp float distance = length(vtx);
vtx = normalize(vtx);
- vtx.xy/=1.0-vtx.z;
- vtx.z=(distance/shadow_dual_paraboloid_render_zfar);
- vtx.z=vtx.z * 2.0 - 1.0;
+ vtx.xy /= 1.0 - vtx.z;
+ vtx.z = (distance / shadow_dual_paraboloid_render_zfar);
+ vtx.z = vtx.z * 2.0 - 1.0;
vertex_interp = vtx;
-
#else
float z_ofs = z_offset;
- z_ofs += (1.0-abs(normal_interp.z))*z_slope_scale;
- vertex_interp.z-=z_ofs;
+ z_ofs += (1.0 - abs(normal_interp.z)) * z_slope_scale;
+ vertex_interp.z -= z_ofs;
#endif //RENDER_DEPTH_DUAL_PARABOLOID
#endif //RENDER_DEPTH
- gl_Position = projection_matrix * vec4(vertex_interp,1.0);
+ gl_Position = projection_matrix * vec4(vertex_interp, 1.0);
- position_interp=gl_Position;
+ position_interp = gl_Position;
#ifdef USE_VERTEX_LIGHTING
- diffuse_light_interp=vec4(0.0);
- specular_light_interp=vec4(0.0);
+ diffuse_light_interp = vec4(0.0);
+ specular_light_interp = vec4(0.0);
#ifdef USE_FORWARD_LIGHTING
- for(int i=0;i<omni_light_count;i++) {
- light_process_omni(omni_light_indices[i],vertex_interp,-normalize( vertex_interp ),normal_interp,roughness,diffuse_light_interp.rgb,specular_light_interp.rgb);
+ for (int i = 0; i < omni_light_count; i++) {
+ light_process_omni(omni_light_indices[i], vertex_interp, -normalize(vertex_interp), normal_interp, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb);
}
- for(int i=0;i<spot_light_count;i++) {
- light_process_spot(spot_light_indices[i],vertex_interp,-normalize( vertex_interp ),normal_interp,roughness,diffuse_light_interp.rgb,specular_light_interp.rgb);
+ for (int i = 0; i < spot_light_count; i++) {
+ light_process_spot(spot_light_indices[i], vertex_interp, -normalize(vertex_interp), normal_interp, roughness, diffuse_light_interp.rgb, specular_light_interp.rgb);
}
#endif
@@ -482,36 +484,34 @@ VERTEX_SHADER_CODE
vec3 directional_diffuse = vec3(0.0);
vec3 directional_specular = vec3(0.0);
- light_compute(normal_interp,-light_direction_attenuation.xyz,-normalize( vertex_interp ),light_color_energy.rgb,roughness,directional_diffuse,directional_specular);
+ light_compute(normal_interp, -light_direction_attenuation.xyz, -normalize(vertex_interp), light_color_energy.rgb, roughness, directional_diffuse, directional_specular);
- float diff_avg = dot(diffuse_light_interp.rgb,vec3(0.33333));
- float diff_dir_avg = dot(directional_diffuse,vec3(0.33333));
- if (diff_avg>0.0) {
- diffuse_light_interp.a=diff_dir_avg/(diff_avg+diff_dir_avg);
+ float diff_avg = dot(diffuse_light_interp.rgb, vec3(0.33333));
+ float diff_dir_avg = dot(directional_diffuse, vec3(0.33333));
+ if (diff_avg > 0.0) {
+ diffuse_light_interp.a = diff_dir_avg / (diff_avg + diff_dir_avg);
} else {
- diffuse_light_interp.a=1.0;
+ diffuse_light_interp.a = 1.0;
}
- diffuse_light_interp.rgb+=directional_diffuse;
+ diffuse_light_interp.rgb += directional_diffuse;
- float spec_avg = dot(specular_light_interp.rgb,vec3(0.33333));
- float spec_dir_avg = dot(directional_specular,vec3(0.33333));
- if (spec_avg>0.0) {
- specular_light_interp.a=spec_dir_avg/(spec_avg+spec_dir_avg);
+ float spec_avg = dot(specular_light_interp.rgb, vec3(0.33333));
+ float spec_dir_avg = dot(directional_specular, vec3(0.33333));
+ if (spec_avg > 0.0) {
+ specular_light_interp.a = spec_dir_avg / (spec_avg + spec_dir_avg);
} else {
- specular_light_interp.a=1.0;
+ specular_light_interp.a = 1.0;
}
- specular_light_interp.rgb+=directional_specular;
+ specular_light_interp.rgb += directional_specular;
#endif //USE_LIGHT_DIRECTIONAL
-
#endif // USE_VERTEX_LIGHTING
-
}
-
+/* clang-format off */
[fragment]
/* texture unit usage, N is max_texture_unity-N
@@ -530,6 +530,7 @@ VERTEX_SHADER_CODE
*/
uniform highp mat4 world_transform;
+/* clang-format on */
#define M_PI 3.14159265359
@@ -555,42 +556,33 @@ in vec3 binormal_interp;
in highp vec3 vertex_interp;
in vec3 normal_interp;
-
/* PBR CHANNELS */
-//used on forward mainly
-uniform bool no_ambient_light;
-
-
-
#ifdef USE_RADIANCE_MAP
-
-
-layout(std140) uniform Radiance { //ubo:2
+layout(std140) uniform Radiance { // ubo:2
mat4 radiance_inverse_xform;
float radiance_ambient_contribution;
-
};
#define RADIANCE_MAX_LOD 5.0
#ifdef USE_RADIANCE_MAP_ARRAY
-uniform sampler2DArray radiance_map; //texunit:-2
+uniform sampler2DArray radiance_map; // texunit:-2
-vec3 textureDualParaboloid(sampler2DArray p_tex, vec3 p_vec,float p_roughness) {
+vec3 textureDualParaboloid(sampler2DArray p_tex, vec3 p_vec, float p_roughness) {
vec3 norm = normalize(p_vec);
- norm.xy/=1.0+abs(norm.z);
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
+ norm.xy /= 1.0 + abs(norm.z);
+ norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25);
// we need to lie the derivatives (normg) and assume that DP side is always the same
// to get proper texture filtering
- vec2 normg=norm.xy;
- if (norm.z>0.0) {
- norm.y=0.5-norm.y+0.5;
+ vec2 normg = norm.xy;
+ if (norm.z > 0.0) {
+ norm.y = 0.5 - norm.y + 0.5;
}
// thanks to OpenGL spec using floor(layer + 0.5) for texture arrays,
@@ -599,22 +591,22 @@ vec3 textureDualParaboloid(sampler2DArray p_tex, vec3 p_vec,float p_roughness) {
float index = p_roughness * RADIANCE_MAX_LOD;
int indexi = int(index * 256.0);
- vec3 base = textureGrad(p_tex, vec3(norm.xy, float(indexi/256)),dFdx(normg),dFdy(normg)).xyz;
- vec3 next = textureGrad(p_tex, vec3(norm.xy, float(indexi/256+1)),dFdx(normg),dFdy(normg)).xyz;
- return mix(base,next,float(indexi%256)/256.0);
+ vec3 base = textureGrad(p_tex, vec3(norm.xy, float(indexi / 256)), dFdx(normg), dFdy(normg)).xyz;
+ vec3 next = textureGrad(p_tex, vec3(norm.xy, float(indexi / 256 + 1)), dFdx(normg), dFdy(normg)).xyz;
+ return mix(base, next, float(indexi % 256) / 256.0);
}
#else
-uniform sampler2D radiance_map; //texunit:-2
+uniform sampler2D radiance_map; // texunit:-2
-vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec,float p_roughness) {
+vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec, float p_roughness) {
vec3 norm = normalize(p_vec);
- norm.xy/=1.0+abs(norm.z);
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
- if (norm.z>0.0) {
- norm.y=0.5-norm.y+0.5;
+ norm.xy /= 1.0 + abs(norm.z);
+ norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25);
+ if (norm.z > 0.0) {
+ norm.y = 0.5 - norm.y + 0.5;
}
return textureLod(p_tex, norm.xy, p_roughness * RADIANCE_MAX_LOD).xyz;
}
@@ -625,20 +617,24 @@ vec3 textureDualParaboloid(sampler2D p_tex, vec3 p_vec,float p_roughness) {
/* Material Uniforms */
-
-
#if defined(USE_MATERIAL)
+/* clang-format off */
layout(std140) uniform UniformData {
MATERIAL_UNIFORMS
};
+/* clang-format on */
#endif
+/* clang-format off */
+
FRAGMENT_SHADER_GLOBALS
+/* clang-format on */
+
layout(std140) uniform SceneData {
highp mat4 projection_matrix;
@@ -670,6 +666,8 @@ layout(std140) uniform SceneData {
mediump float reflection_multiplier;
mediump float subsurface_scatter_width;
mediump float ambient_occlusion_affect_light;
+ mediump float ambient_occlusion_affect_ao_channel;
+ mediump float opaque_prepass_threshold;
bool fog_depth_enabled;
highp float fog_depth_begin;
@@ -682,7 +680,7 @@ layout(std140) uniform SceneData {
highp float fog_height_curve;
};
-//directional light data
+ //directional light data
#ifdef USE_LIGHT_DIRECTIONAL
@@ -691,7 +689,7 @@ layout(std140) uniform DirectionalLightData {
highp vec4 light_pos_inv_radius;
mediump vec4 light_direction_attenuation;
mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
+ mediump vec4 light_params; // cone attenuation, angle, specular, shadow enabled,
mediump vec4 light_clamp;
mediump vec4 shadow_color_contact;
highp mat4 shadow_matrix1;
@@ -701,8 +699,7 @@ layout(std140) uniform DirectionalLightData {
mediump vec4 shadow_split_offsets;
};
-
-uniform highp sampler2DShadow directional_shadow; //texunit:-4
+uniform highp sampler2DShadow directional_shadow; // texunit:-4
#endif
@@ -710,52 +707,47 @@ uniform highp sampler2DShadow directional_shadow; //texunit:-4
in vec4 diffuse_light_interp;
in vec4 specular_light_interp;
#endif
-//omni and spot
+// omni and spot
struct LightData {
highp vec4 light_pos_inv_radius;
mediump vec4 light_direction_attenuation;
mediump vec4 light_color_energy;
- mediump vec4 light_params; //cone attenuation, angle, specular, shadow enabled,
+ mediump vec4 light_params; // cone attenuation, angle, specular, shadow enabled,
mediump vec4 light_clamp;
mediump vec4 shadow_color_contact;
highp mat4 shadow_matrix;
-
};
-
-layout(std140) uniform OmniLightData { //ubo:4
+layout(std140) uniform OmniLightData { // ubo:4
LightData omni_lights[MAX_LIGHT_DATA_STRUCTS];
};
-layout(std140) uniform SpotLightData { //ubo:5
+layout(std140) uniform SpotLightData { // ubo:5
LightData spot_lights[MAX_LIGHT_DATA_STRUCTS];
};
-
-uniform highp sampler2DShadow shadow_atlas; //texunit:-5
-
+uniform highp sampler2DShadow shadow_atlas; // texunit:-5
struct ReflectionData {
mediump vec4 box_extents;
mediump vec4 box_offset;
mediump vec4 params; // intensity, 0, interior , boxproject
- mediump vec4 ambient; //ambient color, energy
+ mediump vec4 ambient; // ambient color, energy
mediump vec4 atlas_clamp;
- highp mat4 local_matrix; //up to here for spot and omni, rest is for directional
- //notes: for ambientblend, use distance to edge to blend between already existing global environment
+ highp mat4 local_matrix; // up to here for spot and omni, rest is for directional
+ // notes: for ambientblend, use distance to edge to blend between already existing global environment
};
layout(std140) uniform ReflectionProbeData { //ubo:6
ReflectionData reflections[MAX_REFLECTION_DATA_STRUCTS];
};
-uniform mediump sampler2D reflection_atlas; //texunit:-3
-
+uniform mediump sampler2D reflection_atlas; // texunit:-3
#ifdef USE_FORWARD_LIGHTING
@@ -770,39 +762,38 @@ uniform int reflection_count;
#endif
-
#if defined(SCREEN_TEXTURE_USED)
-uniform highp sampler2D screen_texture; //texunit:-7
+uniform highp sampler2D screen_texture; // texunit:-7
#endif
#ifdef USE_MULTIPLE_RENDER_TARGETS
-layout(location=0) out vec4 diffuse_buffer;
-layout(location=1) out vec4 specular_buffer;
-layout(location=2) out vec4 normal_mr_buffer;
+layout(location = 0) out vec4 diffuse_buffer;
+layout(location = 1) out vec4 specular_buffer;
+layout(location = 2) out vec4 normal_mr_buffer;
#if defined(ENABLE_SSS)
-layout(location=3) out float sss_buffer;
+layout(location = 3) out float sss_buffer;
#endif
#else
-layout(location=0) out vec4 frag_color;
+layout(location = 0) out vec4 frag_color;
#endif
in highp vec4 position_interp;
-uniform highp sampler2D depth_buffer; //texunit:-8
+uniform highp sampler2D depth_buffer; // texunit:-8
#ifdef USE_CONTACT_SHADOWS
float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) {
- if (abs(dir.z)>0.99)
+ if (abs(dir.z) > 0.99)
return 1.0;
- vec3 endpoint = pos+dir*max_distance;
+ vec3 endpoint = pos + dir * max_distance;
vec4 source = position_interp;
vec4 dest = projection_matrix * vec4(endpoint, 1.0);
@@ -811,51 +802,48 @@ float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) {
vec2 screen_rel = to_screen - from_screen;
- if (length(screen_rel)<0.00001)
- return 1.0; //too small, don't do anything
+ if (length(screen_rel) < 0.00001)
+ return 1.0; // too small, don't do anything
- /*float pixel_size; //approximate pixel size
+ /*
+ float pixel_size; // approximate pixel size
if (screen_rel.x > screen_rel.y) {
- pixel_size = abs((pos.x-endpoint.x)/(screen_rel.x/screen_pixel_size.x));
+ pixel_size = abs((pos.x - endpoint.x) / (screen_rel.x / screen_pixel_size.x));
} else {
- pixel_size = abs((pos.y-endpoint.y)/(screen_rel.y/screen_pixel_size.y));
-
- }*/
- vec4 bias = projection_matrix * vec4(pos+vec3(0.0,0.0,max_distance*0.5), 1.0); //todo un-harcode the 0.04
-
-
-
- vec2 pixel_incr = normalize(screen_rel)*screen_pixel_size;
+ pixel_size = abs((pos.y - endpoint.y) / (screen_rel.y / screen_pixel_size.y));
+ }
+ */
+ vec4 bias = projection_matrix * vec4(pos + vec3(0.0, 0.0, max_distance * 0.5), 1.0);
+ vec2 pixel_incr = normalize(screen_rel) * screen_pixel_size;
float steps = length(screen_rel) / length(pixel_incr);
- steps = min(2000.0,steps); //put a limit to avoid freezing in some strange situation
- //steps=10.0;
+ steps = min(2000.0, steps); // put a limit to avoid freezing in some strange situation
+ //steps = 10.0;
- vec4 incr = (dest - source)/steps;
- float ratio=0.0;
- float ratio_incr = 1.0/steps;
+ vec4 incr = (dest - source) / steps;
+ float ratio = 0.0;
+ float ratio_incr = 1.0 / steps;
- while(steps>0.0) {
- source += incr*2.0;
- bias+=incr*2.0;
+ while (steps > 0.0) {
+ source += incr * 2.0;
+ bias += incr * 2.0;
vec3 uv_depth = (source.xyz / source.w) * 0.5 + 0.5;
- float depth = texture(depth_buffer,uv_depth.xy).r;
+ float depth = texture(depth_buffer, uv_depth.xy).r;
if (depth < uv_depth.z) {
- if (depth > (bias.z/bias.w) * 0.5 + 0.5) {
- return min(pow(ratio,4.0),1.0);
+ if (depth > (bias.z / bias.w) * 0.5 + 0.5) {
+ return min(pow(ratio, 4.0), 1.0);
} else {
return 1.0;
}
}
-
- ratio+=ratio_incr;
- steps-=1.0;
+ ratio += ratio_incr;
+ steps -= 1.0;
}
return 1.0;
@@ -863,7 +851,6 @@ float contact_shadow_compute(vec3 pos, vec3 dir, float max_distance) {
#endif
-
// This returns the G_GGX function divided by 2 cos_theta_m, where in practice cos_theta_m is either N.L or N.V.
// We're dividing this factor off because the overall term we'll end up looks like
// (see, for example, the first unnumbered equation in B. Burley, "Physically Based Shading at Disney", SIGGRAPH 2012):
@@ -885,51 +872,48 @@ float G_GGX_2cos(float cos_theta_m, float alpha) {
// C. Schlick, "An Inexpensive BRDF Model for Physically-based Rendering", Computer Graphics Forum. 13 (3): 233 (1994)
// Eq. (19), although see Heitz (2014) the about the problems with his derivation.
// It nevertheless approximates GGX well with k = alpha/2.
- float k = 0.5*alpha;
+ float k = 0.5 * alpha;
return 0.5 / (cos_theta_m * (1.0 - k) + k);
- // float cos2 = cos_theta_m*cos_theta_m;
- // float sin2 = (1.0-cos2);
- // return 1.0 /( cos_theta_m + sqrt(cos2 + alpha*alpha*sin2) );
+ // float cos2 = cos_theta_m * cos_theta_m;
+ // float sin2 = (1.0 - cos2);
+ // return 1.0 / (cos_theta_m + sqrt(cos2 + alpha * alpha * sin2));
}
float D_GGX(float cos_theta_m, float alpha) {
- float alpha2 = alpha*alpha;
- float d = 1.0 + (alpha2-1.0)*cos_theta_m*cos_theta_m;
- return alpha2/(M_PI * d * d);
+ float alpha2 = alpha * alpha;
+ float d = 1.0 + (alpha2 - 1.0) * cos_theta_m * cos_theta_m;
+ return alpha2 / (M_PI * d * d);
}
float G_GGX_anisotropic_2cos(float cos_theta_m, float alpha_x, float alpha_y, float cos_phi, float sin_phi) {
float cos2 = cos_theta_m * cos_theta_m;
- float sin2 = (1.0-cos2);
+ float sin2 = (1.0 - cos2);
float s_x = alpha_x * cos_phi;
float s_y = alpha_y * sin_phi;
- return 1.0 / max(cos_theta_m + sqrt(cos2 + (s_x*s_x + s_y*s_y)*sin2 ), 0.001);
+ 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;
- 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);
+ float sin2 = (1.0 - cos2);
+ float r_x = cos_phi / alpha_x;
+ float r_y = sin_phi / alpha_y;
+ float d = cos2 + sin2 * (r_x * r_x + r_y * r_y);
return 1.0 / max(M_PI * alpha_x * alpha_y * d * d, 0.001);
}
-
-float SchlickFresnel(float u)
-{
- float m = 1.0-u;
- float m2 = m*m;
- return m2*m2*m; // pow(m,5)
+float SchlickFresnel(float u) {
+ float m = 1.0 - u;
+ float m2 = m * m;
+ return m2 * m2 * m; // pow(m,5)
}
-float GTR1(float NdotH, float a)
-{
- if (a >= 1.0) return 1.0/M_PI;
- float a2 = a*a;
- float t = 1.0 + (a2-1.0)*NdotH*NdotH;
- return (a2-1.0) / (M_PI*log(a2)*t);
+float GTR1(float NdotH, float a) {
+ if (a >= 1.0) return 1.0 / M_PI;
+ float a2 = a * a;
+ float t = 1.0 + (a2 - 1.0) * NdotH * NdotH;
+ return (a2 - 1.0) / (M_PI * log(a2) * t);
}
vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) {
@@ -941,18 +925,21 @@ vec3 metallic_to_specular_color(float metallic, float specular, vec3 albedo) {
void light_compute(vec3 N, vec3 L, vec3 V, vec3 B, vec3 T, vec3 light_color, vec3 attenuation, vec3 diffuse_color, vec3 transmission, float specular_blob_intensity, float roughness, float metallic, float rim, float rim_tint, float clearcoat, float clearcoat_gloss, float anisotropy, inout vec3 diffuse_light, inout vec3 specular_light) {
#if defined(USE_LIGHT_SHADER_CODE)
-//light is written by the light shader
+ // light is written by the light shader
vec3 normal = N;
vec3 albedo = diffuse_color;
vec3 light = L;
vec3 view = V;
+ /* clang-format off */
+
LIGHT_SHADER_CODE
+ /* clang-format on */
#else
- float NdotL = dot(N,L);
+ float NdotL = dot(N, L);
float cNdotL = max(NdotL, 0.0); // clamped NdotL
float NdotV = dot(N, V);
float cNdotV = max(NdotV, 0.0);
@@ -964,10 +951,9 @@ LIGHT_SHADER_CODE
float diffuse_brdf_NL; // BRDF times N.L for calculating diffuse radiance
#endif
-
#if defined(DIFFUSE_LAMBERT_WRAP)
- //energy conserving lambert wrap shader
- diffuse_brdf_NL = max(0.0,(NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
+ // energy conserving lambert wrap shader
+ diffuse_brdf_NL = max(0.0, (NdotL + roughness) / ((1.0 + roughness) * (1.0 + roughness)));
#elif defined(DIFFUSE_OREN_NAYAR)
@@ -975,12 +961,11 @@ LIGHT_SHADER_CODE
// see http://mimosa-pudica.net/improved-oren-nayar.html
float LdotV = dot(L, V);
-
float s = LdotV - NdotL * NdotV;
float t = mix(1.0, max(NdotL, NdotV), step(0.0, s));
float sigma2 = roughness * roughness; // TODO: this needs checking
- vec3 A = 1.0 + sigma2 * (- 0.5 / (sigma2 + 0.33) + 0.17*diffuse_color / (sigma2 + 0.13) );
+ vec3 A = 1.0 + sigma2 * (-0.5 / (sigma2 + 0.33) + 0.17 * diffuse_color / (sigma2 + 0.13));
float B = 0.45 * sigma2 / (sigma2 + 0.09);
diffuse_brdf_NL = cNdotL * (A + vec3(B) * s / t) * (1.0 / M_PI);
@@ -988,21 +973,20 @@ LIGHT_SHADER_CODE
#elif defined(DIFFUSE_TOON)
- diffuse_brdf_NL = smoothstep(-roughness,max(roughness,0.01),NdotL);
+ diffuse_brdf_NL = smoothstep(-roughness, max(roughness, 0.01), NdotL);
#elif defined(DIFFUSE_BURLEY)
{
-
vec3 H = normalize(V + L);
- float cLdotH = max(0.0,dot(L, H));
+ float cLdotH = max(0.0, dot(L, H));
float FD90 = 0.5 + 2.0 * cLdotH * cLdotH * roughness;
float FdV = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotV);
float FdL = 1.0 + (FD90 - 1.0) * SchlickFresnel(cNdotL);
diffuse_brdf_NL = (1.0 / M_PI) * FdV * FdL * cNdotL;
- /*
+ /*
float energyBias = mix(roughness, 0.0, 0.5);
float energyFactor = mix(roughness, 1.0, 1.0 / 1.51);
float fd90 = energyBias + 2.0 * VoH * VoH * roughness;
@@ -1010,84 +994,81 @@ LIGHT_SHADER_CODE
float lightScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotL, 5.0);
float viewScatter = f0 + (fd90 - f0) * pow(1.0 - cNdotV, 5.0);
- diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;*/
+ diffuse_brdf_NL = lightScatter * viewScatter * energyFactor;
+ */
}
#else
- //lambert
+ // lambert
diffuse_brdf_NL = cNdotL * (1.0 / M_PI);
#endif
-#if defined(TRANSMISSION_USED)
- diffuse_light += light_color * diffuse_color * mix(vec3(diffuse_brdf_NL), vec3(M_PI), transmission) * attenuation;
-#else
diffuse_light += light_color * diffuse_color * diffuse_brdf_NL * attenuation;
-#endif
-
+#if defined(TRANSMISSION_USED)
+ diffuse_light += light_color * diffuse_color * (vec3(1.0 / M_PI) - diffuse_brdf_NL) * transmission * attenuation;
+#endif
#if defined(LIGHT_USE_RIM)
- float rim_light = pow(max(0.0,1.0-cNdotV), max(0.0,(1.0-roughness)*16.0));
- diffuse_light += rim_light * rim * mix(vec3(1.0),diffuse_color,rim_tint) * light_color;
+ float rim_light = pow(max(0.0, 1.0 - cNdotV), max(0.0, (1.0 - roughness) * 16.0));
+ diffuse_light += rim_light * rim * mix(vec3(1.0), diffuse_color, rim_tint) * light_color;
#endif
}
-
if (roughness > 0.0) { // FIXME: roughness == 0 should not disable specular light entirely
-
// D
#if defined(SPECULAR_BLINN)
vec3 H = normalize(V + L);
- float cNdotH = max(dot(N,H), 0.0 );
- float intensity = pow( cNdotH, (1.0-roughness) * 256.0);
+ float cNdotH = max(dot(N, H), 0.0);
+ float intensity = pow(cNdotH, (1.0 - roughness) * 256.0);
specular_light += light_color * intensity * specular_blob_intensity * attenuation;
#elif defined(SPECULAR_PHONG)
- vec3 R = normalize(-reflect(L,N));
- float cRdotV = max(0.0,dot(R,V));
- float intensity = pow( cRdotV, (1.0-roughness) * 256.0);
- specular_light += light_color * intensity * specular_blob_intensity * attenuation;
+ vec3 R = normalize(-reflect(L, N));
+ float cRdotV = max(0.0, dot(R, V));
+ float intensity = pow(cRdotV, (1.0 - roughness) * 256.0);
+ specular_light += light_color * intensity * specular_blob_intensity * attenuation;
#elif defined(SPECULAR_TOON)
- vec3 R = normalize(-reflect(L,N));
- float RdotV = dot(R,V);
- float mid = 1.0-roughness;
- mid*=mid;
- float intensity = smoothstep(mid-roughness*0.5, mid+roughness*0.5, RdotV) * mid;
+ vec3 R = normalize(-reflect(L, N));
+ float RdotV = dot(R, V);
+ float mid = 1.0 - roughness;
+ mid *= mid;
+ float intensity = smoothstep(mid - roughness * 0.5, mid + roughness * 0.5, RdotV) * mid;
diffuse_light += light_color * intensity * specular_blob_intensity * attenuation; // write to diffuse_light, as in toon shading you generally want no reflection
#elif defined(SPECULAR_DISABLED)
- //none..
+ // none..
#elif defined(SPECULAR_SCHLICK_GGX)
// shlick+ggx as default
vec3 H = normalize(V + L);
- float cNdotH = max(dot(N,H), 0.0);
- float cLdotH = max(dot(L,H), 0.0);
+ float cNdotH = max(dot(N, H), 0.0);
+ float cLdotH = max(dot(L, H), 0.0);
-# if defined(LIGHT_USE_ANISOTROPY)
+#if defined(LIGHT_USE_ANISOTROPY)
- float aspect = sqrt(1.0-anisotropy*0.9);
- float rx = roughness/aspect;
- float ry = roughness*aspect;
- float ax = rx*rx;
- float ay = ry*ry;
- float XdotH = dot( T, H );
- float YdotH = dot( B, H );
+ 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 XdotH = dot(T, H);
+ float YdotH = dot(B, H);
float D = D_GGX_anisotropic(cNdotH, ax, ay, XdotH, YdotH);
float G = G_GGX_anisotropic_2cos(cNdotL, ax, ay, XdotH, YdotH) * G_GGX_anisotropic_2cos(cNdotV, ax, ay, XdotH, YdotH);
-# else
+#else
float alpha = roughness * roughness;
float D = D_GGX(cNdotH, alpha);
float G = G_GGX_2cos(cNdotL, alpha) * G_GGX_2cos(cNdotV, alpha);
-# endif
+#endif
// F
float F0 = 1.0; // FIXME
float cLdotH5 = SchlickFresnel(cLdotH);
@@ -1100,19 +1081,18 @@ LIGHT_SHADER_CODE
#if defined(LIGHT_USE_CLEARCOAT)
if (clearcoat_gloss > 0.0) {
-# if !defined(SPECULAR_SCHLICK_GGX) && !defined(SPECULAR_BLINN)
+#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);
+#endif
+#if !defined(SPECULAR_SCHLICK_GGX)
+ float cNdotH = max(dot(N, H), 0.0);
+ float cLdotH = max(dot(L, H), 0.0);
float cLdotH5 = SchlickFresnel(cLdotH);
#endif
float Dr = GTR1(cNdotH, mix(.1, .001, clearcoat_gloss));
float Fr = mix(.04, 1.0, cLdotH5);
float Gr = G_GGX_2cos(cNdotL, .25) * G_GGX_2cos(cNdotV, .25);
-
float specular_brdf_NL = 0.25 * clearcoat * Gr * Fr * Dr * cNdotL;
specular_light += specular_brdf_NL * light_color * specular_blob_intensity * attenuation;
@@ -1120,45 +1100,42 @@ LIGHT_SHADER_CODE
#endif
}
-
#endif //defined(USE_LIGHT_SHADER_CODE)
}
-
float sample_shadow(highp sampler2DShadow shadow, vec2 shadow_pixel_size, vec2 pos, float depth, vec4 clamp_rect) {
#ifdef SHADOW_MODE_PCF_13
- float avg=textureProj(shadow,vec4(pos,depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,-shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x*2.0,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x*2.0,0.0),depth,1.0));
- 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);
+ float avg = textureProj(shadow, vec4(pos, depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x, shadow_pixel_size.y), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x, -shadow_pixel_size.y), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x * 2.0, 0.0), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x * 2.0, 0.0), depth, 1.0));
+ 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);
#elif defined(SHADOW_MODE_PCF_5)
- float avg=textureProj(shadow,vec4(pos,depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(shadow_pixel_size.x,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(-shadow_pixel_size.x,0.0),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(0.0,shadow_pixel_size.y),depth,1.0));
- avg+=textureProj(shadow,vec4(pos+vec2(0.0,-shadow_pixel_size.y),depth,1.0));
- return avg*(1.0/5.0);
+ float avg = textureProj(shadow, vec4(pos, depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(shadow_pixel_size.x, 0.0), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(-shadow_pixel_size.x, 0.0), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(0.0, shadow_pixel_size.y), depth, 1.0));
+ avg += textureProj(shadow, vec4(pos + vec2(0.0, -shadow_pixel_size.y), depth, 1.0));
+ return avg * (1.0 / 5.0);
#else
- return textureProj(shadow,vec4(pos,depth,1.0));
+ return textureProj(shadow, vec4(pos, depth, 1.0));
#endif
-
}
#ifdef RENDER_DEPTH_DUAL_PARABOLOID
@@ -1167,239 +1144,227 @@ in highp float dp_clip;
#endif
-
-
#if 0
-//need to save texture depth for this
-
+// need to save texture depth for this
vec3 light_transmittance(float translucency,vec3 light_vec, vec3 normal, vec3 pos, float distance) {
float scale = 8.25 * (1.0 - translucency) / subsurface_scatter_width;
float d = scale * distance;
- /**
- * Armed with the thickness, we can now calculate the color by means of the
- * precalculated transmittance profile.
- * (It can be precomputed into a texture, for maximum performance):
- */
+ /**
+ * Armed with the thickness, we can now calculate the color by means of the
+ * precalculated transmittance profile.
+ * (It can be precomputed into a texture, for maximum performance):
+ */
float dd = -d * d;
- vec3 profile = vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
- vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
- vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
- vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
- vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
- vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
-
- /**
- * Using the profile, we finally approximate the transmitted lighting from
- * the back of the object:
- */
- return profile * clamp(0.3 + dot(light_vec, normal),0.0,1.0);
+ vec3 profile =
+ vec3(0.233, 0.455, 0.649) * exp(dd / 0.0064) +
+ vec3(0.1, 0.336, 0.344) * exp(dd / 0.0484) +
+ vec3(0.118, 0.198, 0.0) * exp(dd / 0.187) +
+ vec3(0.113, 0.007, 0.007) * exp(dd / 0.567) +
+ vec3(0.358, 0.004, 0.0) * exp(dd / 1.99) +
+ vec3(0.078, 0.0, 0.0) * exp(dd / 7.41);
+
+ /**
+ * Using the profile, we finally approximate the transmitted lighting from
+ * the back of the object:
+ */
+ return profile * clamp(0.3 + dot(light_vec, normal),0.0,1.0);
}
#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 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 );
- float normalized_distance = light_length*omni_lights[idx].light_pos_inv_radius.w;
- float omni_attenuation = pow( max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w );
+ vec3 light_rel_vec = omni_lights[idx].light_pos_inv_radius.xyz - vertex;
+ float light_length = length(light_rel_vec);
+ float normalized_distance = light_length * omni_lights[idx].light_pos_inv_radius.w;
+ float omni_attenuation = pow(max(1.0 - normalized_distance, 0.0), omni_lights[idx].light_direction_attenuation.w);
vec3 light_attenuation = vec3(omni_attenuation);
#if !defined(SHADOWS_DISABLED)
- if (omni_lights[idx].light_params.w>0.5) {
- //there is a shadowmap
+ if (omni_lights[idx].light_params.w > 0.5) {
+ // there is a shadowmap
- highp vec3 splane=(omni_lights[idx].shadow_matrix * vec4(vertex,1.0)).xyz;
- float shadow_len=length(splane);
- splane=normalize(splane);
- vec4 clamp_rect=omni_lights[idx].light_clamp;
+ highp vec3 splane = (omni_lights[idx].shadow_matrix * vec4(vertex, 1.0)).xyz;
+ float shadow_len = length(splane);
+ splane = normalize(splane);
+ vec4 clamp_rect = omni_lights[idx].light_clamp;
- if (splane.z>=0.0) {
+ if (splane.z >= 0.0) {
- splane.z+=1.0;
+ splane.z += 1.0;
- clamp_rect.y+=clamp_rect.w;
+ clamp_rect.y += clamp_rect.w;
} else {
- splane.z=1.0 - splane.z;
+ splane.z = 1.0 - splane.z;
/*
- if (clamp_rect.z<clamp_rect.w) {
- clamp_rect.x+=clamp_rect.z;
+ if (clamp_rect.z < clamp_rect.w) {
+ clamp_rect.x += clamp_rect.z;
} else {
- clamp_rect.y+=clamp_rect.w;
+ clamp_rect.y += clamp_rect.w;
}
*/
-
}
- splane.xy/=splane.z;
- splane.xy=splane.xy * 0.5 + 0.5;
+ splane.xy /= splane.z;
+ splane.xy = splane.xy * 0.5 + 0.5;
splane.z = shadow_len * omni_lights[idx].light_pos_inv_radius.w;
- splane.xy = clamp_rect.xy+splane.xy*clamp_rect.zw;
- float shadow = sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,clamp_rect);
+ splane.xy = clamp_rect.xy + splane.xy * clamp_rect.zw;
+ float shadow = sample_shadow(shadow_atlas, shadow_atlas_pixel_size, splane.xy, splane.z, clamp_rect);
#ifdef USE_CONTACT_SHADOWS
- if (shadow>0.01 && omni_lights[idx].shadow_color_contact.a>0.0) {
-
- float contact_shadow = contact_shadow_compute(vertex,normalize(light_rel_vec),min(light_length,omni_lights[idx].shadow_color_contact.a));
- shadow=min(shadow,contact_shadow);
+ if (shadow > 0.01 && omni_lights[idx].shadow_color_contact.a > 0.0) {
+ float contact_shadow = contact_shadow_compute(vertex, normalize(light_rel_vec), min(light_length, omni_lights[idx].shadow_color_contact.a));
+ shadow = min(shadow, contact_shadow);
}
#endif
- light_attenuation*=mix(omni_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow);
+ 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, 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 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 );
- float normalized_distance = light_length*spot_lights[idx].light_pos_inv_radius.w;
- float spot_attenuation = pow( max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w );
+ vec3 light_rel_vec = spot_lights[idx].light_pos_inv_radius.xyz - vertex;
+ float light_length = length(light_rel_vec);
+ float normalized_distance = light_length * spot_lights[idx].light_pos_inv_radius.w;
+ float spot_attenuation = pow(max(1.0 - normalized_distance, 0.001), spot_lights[idx].light_direction_attenuation.w);
vec3 spot_dir = spot_lights[idx].light_direction_attenuation.xyz;
- float spot_cutoff=spot_lights[idx].light_params.y;
- float scos = max(dot(-normalize(light_rel_vec), spot_dir),spot_cutoff);
- float spot_rim = max(0.0001,(1.0 - scos) / (1.0 - spot_cutoff));
- spot_attenuation*= 1.0 - pow( spot_rim, spot_lights[idx].light_params.x);
+ float spot_cutoff = spot_lights[idx].light_params.y;
+ float scos = max(dot(-normalize(light_rel_vec), spot_dir), spot_cutoff);
+ float spot_rim = max(0.0001, (1.0 - scos) / (1.0 - spot_cutoff));
+ spot_attenuation *= 1.0 - pow(spot_rim, spot_lights[idx].light_params.x);
vec3 light_attenuation = vec3(spot_attenuation);
#if !defined(SHADOWS_DISABLED)
- if (spot_lights[idx].light_params.w>0.5) {
+ if (spot_lights[idx].light_params.w > 0.5) {
//there is a shadowmap
- highp vec4 splane=(spot_lights[idx].shadow_matrix * vec4(vertex,1.0));
- splane.xyz/=splane.w;
+ highp vec4 splane = (spot_lights[idx].shadow_matrix * vec4(vertex, 1.0));
+ splane.xyz /= splane.w;
- float shadow = sample_shadow(shadow_atlas,shadow_atlas_pixel_size,splane.xy,splane.z,spot_lights[idx].light_clamp);
+ float shadow = sample_shadow(shadow_atlas, shadow_atlas_pixel_size, splane.xy, splane.z, spot_lights[idx].light_clamp);
#ifdef USE_CONTACT_SHADOWS
- if (shadow>0.01 && spot_lights[idx].shadow_color_contact.a>0.0) {
-
- float contact_shadow = contact_shadow_compute(vertex,normalize(light_rel_vec),min(light_length,spot_lights[idx].shadow_color_contact.a));
- shadow=min(shadow,contact_shadow);
+ if (shadow > 0.01 && spot_lights[idx].shadow_color_contact.a > 0.0) {
+ float contact_shadow = contact_shadow_compute(vertex, normalize(light_rel_vec), min(light_length, spot_lights[idx].shadow_color_contact.a));
+ shadow = min(shadow, contact_shadow);
}
#endif
- light_attenuation*=mix(spot_lights[idx].shadow_color_contact.rgb,vec3(1.0),shadow);
+ light_attenuation *= mix(spot_lights[idx].shadow_color_contact.rgb, vec3(1.0), shadow);
}
#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, 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) {
+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) {
- vec3 ref_vec = normalize(reflect(vertex,normal));
- vec3 local_pos = (reflections[idx].local_matrix * vec4(vertex,1.0)).xyz;
+ vec3 ref_vec = normalize(reflect(vertex, normal));
+ vec3 local_pos = (reflections[idx].local_matrix * vec4(vertex, 1.0)).xyz;
vec3 box_extents = reflections[idx].box_extents.xyz;
- if (any(greaterThan(abs(local_pos),box_extents))) { //out of the reflection box
+ 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));
+ float blend = max(inner_pos.x, max(inner_pos.y, inner_pos.z));
//make blend more rounded
- blend=mix(length(inner_pos),blend,blend);
- blend*=blend;
- blend=max(0.0, 1.0-blend);
+ blend = mix(length(inner_pos), blend, blend);
+ blend *= blend;
+ blend = max(0.0, 1.0 - blend);
- if (reflections[idx].params.x>0.0){// compute reflection
+ if (reflections[idx].params.x > 0.0) { // compute reflection
- vec3 local_ref_vec = (reflections[idx].local_matrix * vec4(ref_vec,0.0)).xyz;
+ vec3 local_ref_vec = (reflections[idx].local_matrix * vec4(ref_vec, 0.0)).xyz;
if (reflections[idx].params.w > 0.5) { //box project
vec3 nrdir = normalize(local_ref_vec);
- vec3 rbmax = (box_extents - local_pos)/nrdir;
- vec3 rbmin = (-box_extents - local_pos)/nrdir;
-
+ vec3 rbmax = (box_extents - local_pos) / nrdir;
+ vec3 rbmin = (-box_extents - local_pos) / nrdir;
- vec3 rbminmax = mix(rbmin,rbmax,greaterThan(nrdir,vec3(0.0,0.0,0.0)));
+ vec3 rbminmax = mix(rbmin, rbmax, 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;
local_ref_vec = posonbox - reflections[idx].box_offset.xyz;
}
-
- vec4 clamp_rect=reflections[idx].atlas_clamp;
+ vec4 clamp_rect = reflections[idx].atlas_clamp;
vec3 norm = normalize(local_ref_vec);
- norm.xy/=1.0+abs(norm.z);
- norm.xy=norm.xy * vec2(0.5,0.25) + vec2(0.5,0.25);
- if (norm.z>0.0) {
- norm.y=0.5-norm.y+0.5;
+ norm.xy /= 1.0 + abs(norm.z);
+ norm.xy = norm.xy * vec2(0.5, 0.25) + vec2(0.5, 0.25);
+ if (norm.z > 0.0) {
+ norm.y = 0.5 - norm.y + 0.5;
}
- vec2 atlas_uv = norm.xy * clamp_rect.zw + clamp_rect.xy;
- atlas_uv = clamp(atlas_uv,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw);
+ vec2 atlas_uv = norm.xy * clamp_rect.zw + clamp_rect.xy;
+ atlas_uv = clamp(atlas_uv, clamp_rect.xy, clamp_rect.xy + clamp_rect.zw);
highp vec4 reflection;
- reflection.rgb = textureLod(reflection_atlas,atlas_uv,roughness*5.0).rgb;
+ reflection.rgb = textureLod(reflection_atlas, atlas_uv, roughness * 5.0).rgb;
if (reflections[idx].params.z < 0.5) {
- reflection.rgb = mix(skybox,reflection.rgb,blend);
+ reflection.rgb = mix(skybox, reflection.rgb, blend);
}
- reflection.rgb*=reflections[idx].params.x;
+ reflection.rgb *= reflections[idx].params.x;
reflection.a = blend;
- reflection.rgb*=reflection.a;
+ reflection.rgb *= reflection.a;
- reflection_accum+=reflection;
+ reflection_accum += reflection;
}
#ifndef USE_LIGHTMAP
- if (reflections[idx].ambient.a>0.0) { //compute ambient using skybox
+ if (reflections[idx].ambient.a > 0.0) { //compute ambient using skybox
+ vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal, 0.0)).xyz;
- vec3 local_amb_vec = (reflections[idx].local_matrix * vec4(normal,0.0)).xyz;
+ vec3 splane = normalize(local_amb_vec);
+ vec4 clamp_rect = reflections[idx].atlas_clamp;
- vec3 splane=normalize(local_amb_vec);
- vec4 clamp_rect=reflections[idx].atlas_clamp;
-
- splane.z*=-1.0;
- if (splane.z>=0.0) {
- splane.z+=1.0;
- clamp_rect.y+=clamp_rect.w;
+ splane.z *= -1.0;
+ if (splane.z >= 0.0) {
+ splane.z += 1.0;
+ clamp_rect.y += clamp_rect.w;
} else {
- splane.z=1.0 - splane.z;
- splane.y=-splane.y;
+ splane.z = 1.0 - splane.z;
+ splane.y = -splane.y;
}
- splane.xy/=splane.z;
- splane.xy=splane.xy * 0.5 + 0.5;
+ splane.xy /= splane.z;
+ splane.xy = splane.xy * 0.5 + 0.5;
splane.xy = splane.xy * clamp_rect.zw + clamp_rect.xy;
- splane.xy = clamp(splane.xy,clamp_rect.xy,clamp_rect.xy+clamp_rect.zw);
+ splane.xy = clamp(splane.xy, clamp_rect.xy, clamp_rect.xy + clamp_rect.zw);
highp vec4 ambient_out;
- ambient_out.a=blend;
- ambient_out.rgb = textureLod(reflection_atlas,splane.xy,5.0).rgb;
- ambient_out.rgb=mix(reflections[idx].ambient.rgb,ambient_out.rgb,reflections[idx].ambient.a);
+ ambient_out.a = blend;
+ ambient_out.rgb = textureLod(reflection_atlas, splane.xy, 5.0).rgb;
+ ambient_out.rgb = mix(reflections[idx].ambient.rgb, ambient_out.rgb, reflections[idx].ambient.a);
if (reflections[idx].params.z < 0.5) {
- ambient_out.rgb = mix(ambient,ambient_out.rgb,blend);
+ ambient_out.rgb = mix(ambient, ambient_out.rgb, blend);
}
ambient_out.rgb *= ambient_out.a;
- ambient_accum+=ambient_out;
+ ambient_accum += ambient_out;
} else {
highp vec4 ambient_out;
- ambient_out.a=blend;
- ambient_out.rgb=reflections[idx].ambient.rgb;
+ ambient_out.a = blend;
+ ambient_out.rgb = reflections[idx].ambient.rgb;
if (reflections[idx].params.z < 0.5) {
- ambient_out.rgb = mix(ambient,ambient_out.rgb,blend);
+ ambient_out.rgb = mix(ambient, ambient_out.rgb, blend);
}
ambient_out.rgb *= ambient_out.a;
- ambient_accum+=ambient_out;
-
+ ambient_accum += ambient_out;
}
#endif
}
@@ -1438,13 +1403,13 @@ uniform bool gi_probe_blend_ambient2;
vec3 voxel_cone_trace(mediump sampler3D probe, vec3 cell_size, vec3 pos, vec3 ambient, bool blend_ambient, vec3 direction, float tan_half_angle, float max_distance, float p_bias) {
- float dist = p_bias;//1.0; //dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0;
- float alpha=0.0;
+ float dist = p_bias; //1.0; //dot(direction,mix(vec3(-1.0),vec3(1.0),greaterThan(direction,vec3(0.0))))*2.0;
+ float alpha = 0.0;
vec3 color = vec3(0.0);
- while(dist < max_distance && alpha < 0.95) {
+ while (dist < max_distance && alpha < 0.95) {
float diameter = max(1.0, 2.0 * tan_half_angle * dist);
- vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter) );
+ vec4 scolor = textureLod(probe, (pos + dist * direction) * cell_size, log2(diameter));
float a = (1.0 - alpha);
color += scolor.rgb * a;
alpha += a * scolor.a;
@@ -1452,35 +1417,33 @@ vec3 voxel_cone_trace(mediump sampler3D probe, vec3 cell_size, vec3 pos, vec3 am
}
if (blend_ambient) {
- color.rgb = mix(ambient,color.rgb,min(1.0,alpha/0.95));
+ color.rgb = mix(ambient, color.rgb, min(1.0, alpha / 0.95));
}
return color;
}
-void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds,vec3 cell_size,vec3 pos, vec3 ambient, vec3 environment, bool blend_ambient,float multiplier, mat3 normal_mtx,vec3 ref_vec, float roughness,float p_bias,float p_normal_bias, inout vec4 out_spec, inout vec4 out_diff) {
-
-
+void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds, vec3 cell_size, vec3 pos, vec3 ambient, vec3 environment, bool blend_ambient, float multiplier, mat3 normal_mtx, vec3 ref_vec, float roughness, float p_bias, float p_normal_bias, inout vec4 out_spec, inout vec4 out_diff) {
- vec3 probe_pos = (probe_xform * vec4(pos,1.0)).xyz;
- vec3 ref_pos = (probe_xform * vec4(pos+ref_vec,1.0)).xyz;
+ vec3 probe_pos = (probe_xform * vec4(pos, 1.0)).xyz;
+ vec3 ref_pos = (probe_xform * vec4(pos + ref_vec, 1.0)).xyz;
ref_vec = normalize(ref_pos - probe_pos);
- probe_pos+=(probe_xform * vec4(normal_mtx[2],0.0)).xyz*p_normal_bias;
+ probe_pos += (probe_xform * vec4(normal_mtx[2], 0.0)).xyz * p_normal_bias;
-/* out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0);
+ /* out_diff.rgb = voxel_cone_trace(probe,cell_size,probe_pos,normalize((probe_xform * vec4(ref_vec,0.0)).xyz),0.0 ,100.0);
out_diff.a = 1.0;
return;*/
//out_diff = vec4(textureLod(probe,probe_pos*cell_size,3.0).rgb,1.0);
//return;
//this causes corrupted pixels, i have no idea why..
- if (any(bvec2(any(lessThan(probe_pos,vec3(0.0))),any(greaterThan(probe_pos,bounds))))) {
+ if (any(bvec2(any(lessThan(probe_pos, vec3(0.0))), any(greaterThan(probe_pos, bounds))))) {
return;
}
- vec3 blendv = abs(probe_pos/bounds * 2.0 - 1.0);
- float blend = clamp(1.0-max(blendv.x,max(blendv.y,blendv.z)), 0.0, 1.0);
+ vec3 blendv = abs(probe_pos / bounds * 2.0 - 1.0);
+ float blend = clamp(1.0 - max(blendv.x, max(blendv.y, blendv.z)), 0.0, 1.0);
//float blend=1.0;
float max_distance = length(bounds);
@@ -1489,14 +1452,13 @@ void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds,vec
#ifdef VCT_QUALITY_HIGH
#define MAX_CONE_DIRS 6
- vec3 cone_dirs[MAX_CONE_DIRS] = 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 cone_dirs[MAX_CONE_DIRS] = 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));
float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.15, 0.15, 0.15, 0.15, 0.15);
float cone_angle_tan = 0.577;
@@ -1505,54 +1467,50 @@ void gi_probe_compute(mediump sampler3D probe, mat4 probe_xform, vec3 bounds,vec
#define MAX_CONE_DIRS 4
- vec3 cone_dirs[MAX_CONE_DIRS] = vec3[] (
+ vec3 cone_dirs[MAX_CONE_DIRS] = vec3[](
vec3(0.707107, 0, 0.707107),
vec3(0, 0.707107, 0.707107),
vec3(-0.707107, 0, 0.707107),
- vec3(0, -0.707107, 0.707107)
- );
+ vec3(0, -0.707107, 0.707107));
float cone_weights[MAX_CONE_DIRS] = float[](0.25, 0.25, 0.25, 0.25);
float cone_angle_tan = 0.98269;
- max_distance*=0.5;
+ max_distance *= 0.5;
float min_ref_tan = 0.2;
#endif
- vec3 light=vec3(0.0);
- for(int i=0;i<MAX_CONE_DIRS;i++) {
-
- vec3 dir = normalize( (probe_xform * vec4(pos + normal_mtx * cone_dirs[i],1.0)).xyz - probe_pos);
- light+=cone_weights[i] * voxel_cone_trace(probe,cell_size,probe_pos,ambient,blend_ambient,dir,cone_angle_tan,max_distance,p_bias);
+ vec3 light = vec3(0.0);
+ for (int i = 0; i < MAX_CONE_DIRS; i++) {
+ vec3 dir = normalize((probe_xform * vec4(pos + normal_mtx * cone_dirs[i], 1.0)).xyz - probe_pos);
+ light += cone_weights[i] * voxel_cone_trace(probe, cell_size, probe_pos, ambient, blend_ambient, dir, cone_angle_tan, max_distance, p_bias);
}
- light*=multiplier;
+ light *= multiplier;
- out_diff += vec4(light*blend,blend);
+ out_diff += vec4(light * blend, blend);
//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)), max_distance, p_bias);
irr_light *= multiplier;
//irr_light=vec3(0.0);
- out_spec += vec4(irr_light*blend,blend);
-
+ out_spec += vec4(irr_light * blend, blend);
}
-
void gi_probes_compute(vec3 pos, vec3 normal, float roughness, inout vec3 out_specular, inout vec3 out_ambient) {
roughness = roughness * roughness;
- vec3 ref_vec = normalize(reflect(normalize(pos),normal));
+ vec3 ref_vec = normalize(reflect(normalize(pos), normal));
//find arbitrary tangent and bitangent, then build a matrix
vec3 v0 = abs(normal.z) < 0.999 ? vec3(0, 0, 1) : vec3(0, 1, 0);
vec3 tangent = normalize(cross(v0, normal));
vec3 bitangent = normalize(cross(tangent, normal));
- mat3 normal_mat = mat3(tangent,bitangent,normal);
+ mat3 normal_mat = mat3(tangent, bitangent, normal);
vec4 diff_accum = vec4(0.0);
vec4 spec_accum = vec4(0.0);
@@ -1564,85 +1522,81 @@ void gi_probes_compute(vec3 pos, vec3 normal, float roughness, inout vec3 out_sp
out_specular = vec3(0.0);
- gi_probe_compute(gi_probe1,gi_probe_xform1,gi_probe_bounds1,gi_probe_cell_size1,pos,ambient,environment,gi_probe_blend_ambient1,gi_probe_multiplier1,normal_mat,ref_vec,roughness,gi_probe_bias1,gi_probe_normal_bias1,spec_accum,diff_accum);
+ gi_probe_compute(gi_probe1, gi_probe_xform1, gi_probe_bounds1, gi_probe_cell_size1, pos, ambient, environment, gi_probe_blend_ambient1, gi_probe_multiplier1, normal_mat, ref_vec, roughness, gi_probe_bias1, gi_probe_normal_bias1, spec_accum, diff_accum);
if (gi_probe2_enabled) {
- gi_probe_compute(gi_probe2,gi_probe_xform2,gi_probe_bounds2,gi_probe_cell_size2,pos,ambient,environment,gi_probe_blend_ambient2,gi_probe_multiplier2,normal_mat,ref_vec,roughness,gi_probe_bias2,gi_probe_normal_bias2,spec_accum,diff_accum);
+ gi_probe_compute(gi_probe2, gi_probe_xform2, gi_probe_bounds2, gi_probe_cell_size2, pos, ambient, environment, gi_probe_blend_ambient2, gi_probe_multiplier2, normal_mat, ref_vec, roughness, gi_probe_bias2, gi_probe_normal_bias2, spec_accum, diff_accum);
}
- if (diff_accum.a>0.0) {
- diff_accum.rgb/=diff_accum.a;
+ if (diff_accum.a > 0.0) {
+ diff_accum.rgb /= diff_accum.a;
}
- if (spec_accum.a>0.0) {
- spec_accum.rgb/=spec_accum.a;
+ if (spec_accum.a > 0.0) {
+ spec_accum.rgb /= spec_accum.a;
}
- out_specular+=spec_accum.rgb;
- out_ambient+=diff_accum.rgb;
-
+ out_specular += spec_accum.rgb;
+ out_ambient += diff_accum.rgb;
}
#endif
-
-
void main() {
#ifdef RENDER_DEPTH_DUAL_PARABOLOID
- if (dp_clip>0.0)
+ if (dp_clip > 0.0)
discard;
#endif
//lay out everything, whathever is unused is optimized away anyway
highp vec3 vertex = vertex_interp;
- vec3 albedo = vec3(0.8,0.8,0.8);
+ vec3 albedo = vec3(1.0);
vec3 transmission = vec3(0.0);
float metallic = 0.0;
float specular = 0.5;
- vec3 emission = vec3(0.0,0.0,0.0);
+ vec3 emission = vec3(0.0);
float roughness = 1.0;
float rim = 0.0;
float rim_tint = 0.0;
- float clearcoat=0.0;
- float clearcoat_gloss=0.0;
- float anisotropy = 1.0;
- vec2 anisotropy_flow = vec2(1.0,0.0);
+ float clearcoat = 0.0;
+ float clearcoat_gloss = 0.0;
+ float anisotropy = 0.0;
+ vec2 anisotropy_flow = vec2(1.0, 0.0);
#if defined(ENABLE_AO)
- float ao=1.0;
- float ao_light_affect=0.0;
+ float ao = 1.0;
+ float ao_light_affect = 0.0;
#endif
float alpha = 1.0;
#if defined(DO_SIDE_CHECK)
- float side=float(gl_FrontFacing)*2.0-1.0;
+ float side = gl_FrontFacing ? 1.0 : -1.0;
#else
- float side=1.0;
+ 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) * side;
+ vec3 tangent = normalize(tangent_interp) * side;
#else
vec3 binormal = vec3(0.0);
vec3 tangent = vec3(0.0);
#endif
- vec3 normal = normalize(normal_interp)*side;
+ vec3 normal = normalize(normal_interp) * side;
#if defined(ENABLE_UV_INTERP)
vec2 uv = uv_interp;
#endif
-#if defined(ENABLE_UV2_INTERP) || defined (USE_LIGHTMAP)
+#if defined(ENABLE_UV2_INTERP) || defined(USE_LIGHTMAP)
vec2 uv2 = uv2_interp;
#endif
@@ -1655,66 +1609,67 @@ void main() {
vec3 normalmap = vec3(0.5);
#endif
- float normaldepth=1.0;
+ float normaldepth = 1.0;
#if defined(SCREEN_UV_USED)
- vec2 screen_uv = gl_FragCoord.xy*screen_pixel_size;
+ vec2 screen_uv = gl_FragCoord.xy * screen_pixel_size;
#endif
-#if defined (ENABLE_SSS)
- float sss_strength=0.0;
+#if defined(ENABLE_SSS)
+ float sss_strength = 0.0;
#endif
-{
-
+ {
+ /* clang-format off */
FRAGMENT_SHADER_CODE
-}
-
+ /* clang-format on */
+ }
#if defined(ALPHA_SCISSOR_USED)
- if (alpha<alpha_scissor) {
+ if (alpha < alpha_scissor) {
discard;
}
#endif
#ifdef USE_OPAQUE_PREPASS
- if (alpha<0.99) {
+ if (alpha < opaque_prepass_threshold) {
discard;
}
+
#endif
#if defined(ENABLE_NORMALMAP)
- normalmap.xy=normalmap.xy*2.0-1.0;
- normalmap.z=sqrt(1.0-dot(normalmap.xy,normalmap.xy)); //always ignore Z, as it can be RG packed, Z may be pos/neg, etc.
+ 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_interp, tangent * normalmap.x + binormal * normalmap.y + normal * normalmap.z, normaldepth)) * side;
#endif
#if defined(LIGHT_USE_ANISOTROPY)
- if (anisotropy>0.01) {
+ if (anisotropy > 0.01) {
//rotation matrix
- mat3 rot = mat3( tangent, binormal, normal );
+ mat3 rot = mat3(tangent, binormal, normal);
//make local to space
- tangent = normalize(rot * vec3(anisotropy_flow.x,anisotropy_flow.y,0.0));
- binormal = normalize(rot * vec3(-anisotropy_flow.y,anisotropy_flow.x,0.0));
+ tangent = normalize(rot * vec3(anisotropy_flow.x, anisotropy_flow.y, 0.0));
+ binormal = normalize(rot * vec3(-anisotropy_flow.y, anisotropy_flow.x, 0.0));
}
#endif
#ifdef ENABLE_CLIP_ALPHA
- if (albedo.a<0.99) {
+ if (albedo.a < 0.99) {
//used for doublepass and shadowmapping
discard;
}
#endif
-/////////////////////// LIGHTING //////////////////////////////
+ /////////////////////// LIGHTING //////////////////////////////
//apply energy conservation
@@ -1724,68 +1679,65 @@ FRAGMENT_SHADER_CODE
vec3 diffuse_light = diffuse_light_interp.rgb;
#else
- vec3 specular_light = vec3(0.0,0.0,0.0);
- vec3 diffuse_light = vec3(0.0,0.0,0.0);
+ vec3 specular_light = vec3(0.0, 0.0, 0.0);
+ vec3 diffuse_light = vec3(0.0, 0.0, 0.0);
#endif
vec3 ambient_light;
- vec3 env_reflection_light = vec3(0.0,0.0,0.0);
-
- vec3 eye_vec = -normalize( vertex_interp );
-
+ vec3 env_reflection_light = vec3(0.0, 0.0, 0.0);
+ vec3 eye_vec = -normalize(vertex_interp);
#ifdef USE_RADIANCE_MAP
- if (no_ambient_light) {
- ambient_light=vec3(0.0,0.0,0.0);
- } else {
- {
-
- { //read radiance from dual paraboloid
+#ifdef AMBIENT_LIGHT_DISABLED
+ ambient_light = vec3(0.0, 0.0, 0.0);
+#else
+ {
- vec3 ref_vec = reflect(-eye_vec,normal); //2.0 * ndotv * normal - view; // reflect(v, n);
- ref_vec=normalize((radiance_inverse_xform * vec4(ref_vec,0.0)).xyz);
- vec3 radiance = textureDualParaboloid(radiance_map,ref_vec,roughness) * bg_energy;
- env_reflection_light = radiance;
-
- }
- //no longer a cubemap
- //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y);
+ { //read radiance from dual paraboloid
+ vec3 ref_vec = reflect(-eye_vec, normal); //2.0 * ndotv * normal - view; // reflect(v, n);
+ ref_vec = normalize((radiance_inverse_xform * vec4(ref_vec, 0.0)).xyz);
+ vec3 radiance = textureDualParaboloid(radiance_map, ref_vec, roughness) * bg_energy;
+ env_reflection_light = radiance;
}
+ //no longer a cubemap
+ //vec3 radiance = textureLod(radiance_cube, r, lod).xyz * ( brdf.x + brdf.y);
+ }
#ifndef USE_LIGHTMAP
- {
+ {
- vec3 ambient_dir=normalize((radiance_inverse_xform * vec4(normal,0.0)).xyz);
- vec3 env_ambient=textureDualParaboloid(radiance_map,ambient_dir,1.0) * bg_energy;
+ vec3 ambient_dir = normalize((radiance_inverse_xform * vec4(normal, 0.0)).xyz);
+ vec3 env_ambient = textureDualParaboloid(radiance_map, ambient_dir, 1.0) * bg_energy;
- ambient_light=mix(ambient_light_color.rgb,env_ambient,radiance_ambient_contribution);
- //ambient_light=vec3(0.0,0.0,0.0);
- }
-#endif
+ ambient_light = mix(ambient_light_color.rgb, env_ambient, radiance_ambient_contribution);
+ //ambient_light=vec3(0.0,0.0,0.0);
}
+#endif
+#endif //AMBIENT_LIGHT_DISABLED
#else
- if (no_ambient_light){
- ambient_light=vec3(0.0,0.0,0.0);
- } else {
- ambient_light=ambient_light_color.rgb;
- }
+#ifdef AMBIENT_LIGHT_DISABLED
+ ambient_light = vec3(0.0, 0.0, 0.0);
+#else
+ ambient_light = ambient_light_color.rgb;
+#endif //AMBIENT_LIGHT_DISABLED
+
#endif
- ambient_light*=ambient_energy;
+ ambient_light *= ambient_energy;
- float specular_blob_intensity=1.0;
+ float specular_blob_intensity = 1.0;
#if defined(SPECULAR_TOON)
- specular_blob_intensity*=specular * 2.0;
+ specular_blob_intensity *= specular * 2.0;
#endif
#if defined(USE_LIGHT_DIRECTIONAL)
- vec3 light_attenuation=vec3(1.0);
+ vec3 light_attenuation = vec3(1.0);
float depth_z = -vertex.z;
#ifdef LIGHT_DIRECTIONAL_SHADOW
@@ -1799,261 +1751,234 @@ FRAGMENT_SHADER_CODE
if (depth_z < shadow_split_offsets.x) {
#endif //LIGHT_USE_PSSM4
- vec3 pssm_coord;
- float pssm_fade=0.0;
+ vec3 pssm_coord;
+ float pssm_fade = 0.0;
#ifdef LIGHT_USE_PSSM_BLEND
- float pssm_blend;
- vec3 pssm_coord2;
- bool use_blend=true;
+ float pssm_blend;
+ vec3 pssm_coord2;
+ bool use_blend = true;
#endif
-
#ifdef LIGHT_USE_PSSM4
+ if (depth_z < shadow_split_offsets.y) {
- if (depth_z < shadow_split_offsets.y) {
-
- if (depth_z < shadow_split_offsets.x) {
-
- highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
+ if (depth_z < shadow_split_offsets.x) {
+ highp vec4 splane = (shadow_matrix1 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
#if defined(LIGHT_USE_PSSM_BLEND)
- splane=(shadow_matrix2 * vec4(vertex,1.0));
- pssm_coord2=splane.xyz/splane.w;
- pssm_blend=smoothstep(0.0,shadow_split_offsets.x,depth_z);
+ splane = (shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_coord2 = splane.xyz / splane.w;
+ pssm_blend = smoothstep(0.0, shadow_split_offsets.x, depth_z);
#endif
- } else {
+ } else {
- highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
+ highp vec4 splane = (shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
#if defined(LIGHT_USE_PSSM_BLEND)
- splane=(shadow_matrix3 * vec4(vertex,1.0));
- pssm_coord2=splane.xyz/splane.w;
- pssm_blend=smoothstep(shadow_split_offsets.x,shadow_split_offsets.y,depth_z);
+ splane = (shadow_matrix3 * vec4(vertex, 1.0));
+ pssm_coord2 = splane.xyz / splane.w;
+ pssm_blend = smoothstep(shadow_split_offsets.x, shadow_split_offsets.y, depth_z);
#endif
+ }
+ } else {
- }
- } else {
-
-
- if (depth_z < shadow_split_offsets.z) {
+ if (depth_z < shadow_split_offsets.z) {
- highp vec4 splane=(shadow_matrix3 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
+ highp vec4 splane = (shadow_matrix3 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
#if defined(LIGHT_USE_PSSM_BLEND)
- splane=(shadow_matrix4 * vec4(vertex,1.0));
- pssm_coord2=splane.xyz/splane.w;
- pssm_blend=smoothstep(shadow_split_offsets.y,shadow_split_offsets.z,depth_z);
+ splane = (shadow_matrix4 * vec4(vertex, 1.0));
+ pssm_coord2 = splane.xyz / splane.w;
+ pssm_blend = smoothstep(shadow_split_offsets.y, shadow_split_offsets.z, depth_z);
#endif
- } else {
+ } else {
- highp vec4 splane=(shadow_matrix4 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
- pssm_fade = smoothstep(shadow_split_offsets.z,shadow_split_offsets.w,depth_z);
+ highp vec4 splane = (shadow_matrix4 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
+ pssm_fade = smoothstep(shadow_split_offsets.z, shadow_split_offsets.w, depth_z);
#if defined(LIGHT_USE_PSSM_BLEND)
- use_blend=false;
+ use_blend = false;
#endif
-
+ }
}
- }
-
-
#endif //LIGHT_USE_PSSM4
#ifdef LIGHT_USE_PSSM2
- if (depth_z < shadow_split_offsets.x) {
-
- highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
+ if (depth_z < shadow_split_offsets.x) {
+ highp vec4 splane = (shadow_matrix1 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
#if defined(LIGHT_USE_PSSM_BLEND)
- splane=(shadow_matrix2 * vec4(vertex,1.0));
- pssm_coord2=splane.xyz/splane.w;
- pssm_blend=smoothstep(0.0,shadow_split_offsets.x,depth_z);
+ splane = (shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_coord2 = splane.xyz / splane.w;
+ pssm_blend = smoothstep(0.0, shadow_split_offsets.x, depth_z);
#endif
- } else {
- highp vec4 splane=(shadow_matrix2 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
- pssm_fade = smoothstep(shadow_split_offsets.x,shadow_split_offsets.y,depth_z);
+ } else {
+ highp vec4 splane = (shadow_matrix2 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
+ pssm_fade = smoothstep(shadow_split_offsets.x, shadow_split_offsets.y, depth_z);
#if defined(LIGHT_USE_PSSM_BLEND)
- use_blend=false;
+ use_blend = false;
#endif
-
- }
+ }
#endif //LIGHT_USE_PSSM2
#if !defined(LIGHT_USE_PSSM4) && !defined(LIGHT_USE_PSSM2)
- { //regular orthogonal
- highp vec4 splane=(shadow_matrix1 * vec4(vertex,1.0));
- pssm_coord=splane.xyz/splane.w;
- }
+ { //regular orthogonal
+ highp vec4 splane = (shadow_matrix1 * vec4(vertex, 1.0));
+ pssm_coord = splane.xyz / splane.w;
+ }
#endif
+ //one one sample
- //one one sample
-
- float shadow = sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord.xy,pssm_coord.z,light_clamp);
+ float shadow = sample_shadow(directional_shadow, directional_shadow_pixel_size, pssm_coord.xy, pssm_coord.z, light_clamp);
#if defined(LIGHT_USE_PSSM_BLEND)
- if (use_blend) {
- shadow=mix(shadow, sample_shadow(directional_shadow,directional_shadow_pixel_size,pssm_coord2.xy,pssm_coord2.z,light_clamp),pssm_blend);
- }
+ if (use_blend) {
+ shadow = mix(shadow, sample_shadow(directional_shadow, directional_shadow_pixel_size, pssm_coord2.xy, pssm_coord2.z, light_clamp), pssm_blend);
+ }
#endif
#ifdef USE_CONTACT_SHADOWS
- if (shadow>0.01 && shadow_color_contact.a>0.0) {
-
- float contact_shadow = contact_shadow_compute(vertex,-light_direction_attenuation.xyz,shadow_color_contact.a);
- shadow=min(shadow,contact_shadow);
+ if (shadow > 0.01 && shadow_color_contact.a > 0.0) {
- }
+ float contact_shadow = contact_shadow_compute(vertex, -light_direction_attenuation.xyz, shadow_color_contact.a);
+ shadow = min(shadow, contact_shadow);
+ }
#endif
- light_attenuation=mix(mix(shadow_color_contact.rgb,vec3(1.0),shadow),vec3(1.0),pssm_fade);
-
-
+ light_attenuation = mix(mix(shadow_color_contact.rgb, vec3(1.0), shadow), vec3(1.0), pssm_fade);
}
-
#endif // !defined(SHADOWS_DISABLED)
#endif //LIGHT_DIRECTIONAL_SHADOW
#ifdef USE_VERTEX_LIGHTING
- diffuse_light*=mix(vec3(1.0),light_attenuation,diffuse_light_interp.a);
- specular_light*=mix(vec3(1.0),light_attenuation,specular_light_interp.a);
+ diffuse_light *= mix(vec3(1.0), light_attenuation, diffuse_light_interp.a);
+ 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, rim, rim_tint, clearcoat, clearcoat_gloss, anisotropy, diffuse_light, specular_light);
#endif
-
#endif //#USE_LIGHT_DIRECTIONAL
#ifdef USE_GI_PROBES
- gi_probes_compute(vertex,normal,roughness,env_reflection_light,ambient_light);
+ gi_probes_compute(vertex, normal, roughness, env_reflection_light, ambient_light);
#endif
#ifdef USE_LIGHTMAP
- ambient_light = texture(lightmap,uv2).rgb * lightmap_energy;
+ ambient_light = texture(lightmap, uv2).rgb * lightmap_energy;
#endif
#ifdef USE_LIGHTMAP_CAPTURE
{
- vec3 cone_dirs[12] = vec3[] (
- vec3(0, 0, 1),
- vec3(0.866025, 0, 0.5),
- vec3(0.267617, 0.823639, 0.5),
- vec3(-0.700629, 0.509037, 0.5),
- vec3(-0.700629, -0.509037, 0.5),
- vec3(0.267617, -0.823639, 0.5),
- vec3(0, 0, -1),
- vec3(0.866025, 0, -0.5),
- vec3(0.267617, 0.823639, -0.5),
- vec3(-0.700629, 0.509037, -0.5),
- vec3(-0.700629, -0.509037, -0.5),
- vec3(0.267617, -0.823639, -0.5)
- );
-
-
- vec3 local_normal = normalize(camera_matrix * vec4(normal,0.0)).xyz;
+ 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;
+ 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;
+ captured /= sum;
if (lightmap_capture_sky) {
- ambient_light = mix( ambient_light, captured.rgb, captured.a);
+ ambient_light = mix(ambient_light, captured.rgb, captured.a);
} else {
ambient_light = captured.rgb;
}
-
}
#endif
#ifdef USE_FORWARD_LIGHTING
-
- highp vec4 reflection_accum = vec4(0.0,0.0,0.0,0.0);
- highp vec4 ambient_accum = vec4(0.0,0.0,0.0,0.0);
- for(int i=0;i<reflection_count;i++) {
- reflection_process(reflection_indices[i],vertex,normal,binormal,tangent,roughness,anisotropy,ambient_light,env_reflection_light,reflection_accum,ambient_accum);
+ highp vec4 reflection_accum = vec4(0.0, 0.0, 0.0, 0.0);
+ highp vec4 ambient_accum = vec4(0.0, 0.0, 0.0, 0.0);
+ for (int i = 0; i < reflection_count; i++) {
+ reflection_process(reflection_indices[i], vertex, normal, binormal, tangent, roughness, anisotropy, ambient_light, env_reflection_light, reflection_accum, ambient_accum);
}
- if (reflection_accum.a>0.0) {
- specular_light+=reflection_accum.rgb/reflection_accum.a;
+ if (reflection_accum.a > 0.0) {
+ specular_light += reflection_accum.rgb / reflection_accum.a;
} else {
- specular_light+=env_reflection_light;
+ specular_light += env_reflection_light;
}
#ifndef USE_LIGHTMAP
- if (ambient_accum.a>0.0) {
- ambient_light=ambient_accum.rgb/ambient_accum.a;
+ if (ambient_accum.a > 0.0) {
+ ambient_light = ambient_accum.rgb / ambient_accum.a;
}
#endif
-
#ifdef USE_VERTEX_LIGHTING
- diffuse_light*=albedo;
+ diffuse_light *= albedo;
#else
- for(int i=0;i<omni_light_count;i++) {
- light_process_omni(omni_light_indices[i],vertex,eye_vec,normal,binormal,tangent,albedo,transmission,roughness,metallic,rim,rim_tint,clearcoat,clearcoat_gloss,anisotropy,specular_blob_intensity,diffuse_light,specular_light);
+ 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);
}
- 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);
+ 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);
}
#endif //USE_VERTEX_LIGHTING
#endif
-
-
-
#ifdef RENDER_DEPTH
//nothing happens, so a tree-ssa optimizer will result in no fragment shader :)
#else
- specular_light*=reflection_multiplier;
- ambient_light*=albedo; //ambient must be multiplied by albedo at the end
+ specular_light *= reflection_multiplier;
+ ambient_light *= albedo; //ambient must be multiplied by albedo at the end
#if defined(ENABLE_AO)
- ambient_light*=ao;
- ao_light_affect = mix(1.0,ao,ao_light_affect);
- specular_light*=ao_light_affect;
- diffuse_light*=ao_light_affect;
+ ambient_light *= ao;
+ ao_light_affect = mix(1.0, ao, ao_light_affect);
+ specular_light *= ao_light_affect;
+ diffuse_light *= ao_light_affect;
#endif
-
-
//energy conservation
- diffuse_light *= 1.0-metallic; // TODO: avoid all diffuse and ambient light calculations when metallic == 1 up to this point
- ambient_light *= 1.0-metallic;
-
+ 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;
{
@@ -2064,27 +1989,24 @@ FRAGMENT_SHADER_CODE
// Environment brdf approximation (Lazarov 2013)
// see https://www.unrealengine.com/en-US/blog/physically-based-shading-on-mobile
const vec4 c0 = vec4(-1.0, -0.0275, -0.572, 0.022);
- const vec4 c1 = vec4( 1.0, 0.0425, 1.04, -0.04);
+ const vec4 c1 = vec4(1.0, 0.0425, 1.04, -0.04);
vec4 r = roughness * c0 + c1;
- float ndotv = clamp(dot(normal,eye_vec),0.0,1.0);
- float a004 = min( r.x * r.x, exp2( -9.28 * ndotv ) ) * r.x + r.y;
- vec2 AB = vec2( -1.04, 1.04 ) * a004 + r.zw;
+ float ndotv = clamp(dot(normal, eye_vec), 0.0, 1.0);
+ float a004 = min(r.x * r.x, exp2(-9.28 * ndotv)) * r.x + r.y;
+ vec2 AB = vec2(-1.04, 1.04) * a004 + r.zw;
vec3 specular_color = metallic_to_specular_color(metallic, specular, albedo);
specular_light *= AB.x * specular_color + AB.y;
#endif
-
}
if (fog_color_enabled.a > 0.5) {
- float fog_amount=0.0;
-
-
+ float fog_amount = 0.0;
#ifdef USE_LIGHT_DIRECTIONAL
- vec3 fog_color = mix( fog_color_enabled.rgb, fog_sun_color_amount.rgb,fog_sun_color_amount.a * pow(max( dot(normalize(vertex),-light_direction_attenuation.xyz), 0.0),8.0) );
+ vec3 fog_color = mix(fog_color_enabled.rgb, fog_sun_color_amount.rgb, fog_sun_color_amount.a * pow(max(dot(normalize(vertex), -light_direction_attenuation.xyz), 0.0), 8.0));
#else
vec3 fog_color = fog_color_enabled.rgb;
@@ -2094,79 +2016,67 @@ FRAGMENT_SHADER_CODE
if (fog_depth_enabled) {
- float fog_z = smoothstep(fog_depth_begin,z_far,length(vertex));
+ float fog_z = smoothstep(fog_depth_begin, z_far, length(vertex));
- fog_amount = pow(fog_z,fog_depth_curve);
+ fog_amount = pow(fog_z, fog_depth_curve);
if (fog_transmit_enabled) {
vec3 total_light = emission + ambient_light + specular_light + diffuse_light;
- float transmit = pow(fog_z,fog_transmit_curve);
- fog_color = mix(max(total_light,fog_color),fog_color,transmit);
+ float transmit = pow(fog_z, fog_transmit_curve);
+ fog_color = mix(max(total_light, fog_color), fog_color, transmit);
}
}
if (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));
+ 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));
}
float rev_amount = 1.0 - fog_amount;
-
emission = emission * rev_amount + fog_color * fog_amount;
- ambient_light*=rev_amount;
- specular_light*rev_amount;
- diffuse_light*=rev_amount;
-
+ ambient_light *= rev_amount;
+ specular_light *rev_amount;
+ diffuse_light *= rev_amount;
}
#ifdef USE_MULTIPLE_RENDER_TARGETS
-
#ifdef SHADELESS
- diffuse_buffer=vec4(albedo.rgb,0.0);
- specular_buffer=vec4(0.0);
+ diffuse_buffer = vec4(albedo.rgb, 0.0);
+ specular_buffer = vec4(0.0);
#else
-#if defined(ENABLE_AO)
-
- float ambient_scale=0.0; // AO is supplied by material
-#else
//approximate ambient scale for SSAO, since we will lack full ambient
- float max_emission=max(emission.r,max(emission.g,emission.b));
- float max_ambient=max(ambient_light.r,max(ambient_light.g,ambient_light.b));
- float max_diffuse=max(diffuse_light.r,max(diffuse_light.g,diffuse_light.b));
- float total_ambient = max_ambient+max_diffuse+max_emission;
- float ambient_scale = (total_ambient>0.0) ? (max_ambient+ambient_occlusion_affect_light*max_diffuse)/total_ambient : 0.0;
-#endif //ENABLE_AO
+ float max_emission = max(emission.r, max(emission.g, emission.b));
+ float max_ambient = max(ambient_light.r, max(ambient_light.g, ambient_light.b));
+ float max_diffuse = max(diffuse_light.r, max(diffuse_light.g, diffuse_light.b));
+ float total_ambient = max_ambient + max_diffuse + max_emission;
+ float ambient_scale = (total_ambient > 0.0) ? (max_ambient + ambient_occlusion_affect_light * max_diffuse) / total_ambient : 0.0;
- diffuse_buffer=vec4(emission+diffuse_light+ambient_light,ambient_scale);
- specular_buffer=vec4(specular_light,metallic);
+#if defined(ENABLE_AO)
+ ambient_scale = mix(0.0, ambient_scale, ambient_occlusion_affect_ao_channel);
+#endif
+ diffuse_buffer = vec4(emission + diffuse_light + ambient_light, ambient_scale);
+ specular_buffer = vec4(specular_light, metallic);
#endif //SHADELESS
- normal_mr_buffer=vec4(normalize(normal)*0.5+0.5,roughness);
+ normal_mr_buffer = vec4(normalize(normal) * 0.5 + 0.5, roughness);
-#if defined (ENABLE_SSS)
+#if defined(ENABLE_SSS)
sss_buffer = sss_strength;
#endif
-
#else //USE_MULTIPLE_RENDER_TARGETS
-
#ifdef SHADELESS
- frag_color=vec4(albedo,alpha);
+ frag_color = vec4(albedo, alpha);
#else
- frag_color=vec4(emission+ambient_light+diffuse_light+specular_light,alpha);
+ frag_color = vec4(emission + ambient_light + diffuse_light + specular_light, alpha);
#endif //SHADELESS
-
#endif //USE_MULTIPLE_RENDER_TARGETS
-
-
#endif //RENDER_DEPTH
-
-
}
diff --git a/drivers/gles3/shaders/screen_space_reflection.glsl b/drivers/gles3/shaders/screen_space_reflection.glsl
index b2e6f7a736..86546319a0 100644
--- a/drivers/gles3/shaders/screen_space_reflection.glsl
+++ b/drivers/gles3/shaders/screen_space_reflection.glsl
@@ -1,8 +1,9 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
out vec2 pos_interp;
@@ -11,13 +12,14 @@ void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
- pos_interp.xy=gl_Position.xy;
+ pos_interp.xy = gl_Position.xy;
}
+/* clang-format off */
[fragment]
-
in vec2 uv_interp;
+/* clang-format on */
in vec2 pos_interp;
uniform sampler2D source_diffuse; //texunit:0
@@ -40,81 +42,67 @@ uniform float depth_tolerance;
uniform float distance_fade;
uniform float curve_fade_in;
-
layout(location = 0) out vec4 frag_color;
-
-vec2 view_to_screen(vec3 view_pos,out float w) {
- vec4 projected = projection * vec4(view_pos, 1.0);
- projected.xyz /= projected.w;
- projected.xy = projected.xy * 0.5 + 0.5;
- w=projected.w;
- return projected.xy;
+vec2 view_to_screen(vec3 view_pos, out float w) {
+ vec4 projected = projection * vec4(view_pos, 1.0);
+ projected.xyz /= projected.w;
+ projected.xy = projected.xy * 0.5 + 0.5;
+ w = projected.w;
+ return projected.xy;
}
-
-
#define M_PI 3.14159265359
void main() {
-
- ////
-
- vec4 diffuse = texture( source_diffuse, uv_interp );
- vec4 normal_roughness = texture( source_normal_roughness, uv_interp);
+ vec4 diffuse = texture(source_diffuse, uv_interp);
+ vec4 normal_roughness = texture(source_normal_roughness, uv_interp);
vec3 normal;
-
- normal = normal_roughness.xyz*2.0-1.0;
+ normal = normal_roughness.xyz * 2.0 - 1.0;
float roughness = normal_roughness.w;
- float depth_tex = texture(source_depth,uv_interp).r;
+ float depth_tex = texture(source_depth, uv_interp).r;
- vec4 world_pos = inverse_projection * vec4( uv_interp*2.0-1.0, depth_tex*2.0-1.0, 1.0 );
- vec3 vertex = world_pos.xyz/world_pos.w;
+ vec4 world_pos = inverse_projection * vec4(uv_interp * 2.0 - 1.0, depth_tex * 2.0 - 1.0, 1.0);
+ vec3 vertex = world_pos.xyz / world_pos.w;
vec3 view_dir = normalize(vertex);
vec3 ray_dir = normalize(reflect(view_dir, normal));
- if (dot(ray_dir,normal)<0.001) {
- frag_color=vec4(0.0);
+ if (dot(ray_dir, normal) < 0.001) {
+ frag_color = vec4(0.0);
return;
}
//ray_dir = normalize(view_dir - normal * dot(normal,view_dir) * 2.0);
-
- //ray_dir = normalize(vec3(1,1,-1));
-
+ //ray_dir = normalize(vec3(1, 1, -1));
////////////////
-
- //make ray length and clip it against the near plane (don't want to trace beyond visible)
+ // make ray length and clip it against the near plane (don't want to trace beyond visible)
float ray_len = (vertex.z + ray_dir.z * camera_z_far) > -camera_z_near ? (-camera_z_near - vertex.z) / ray_dir.z : camera_z_far;
- vec3 ray_end = vertex + ray_dir*ray_len;
+ vec3 ray_end = vertex + ray_dir * ray_len;
float w_begin;
- vec2 vp_line_begin = view_to_screen(vertex,w_begin);
+ vec2 vp_line_begin = view_to_screen(vertex, w_begin);
float w_end;
- vec2 vp_line_end = view_to_screen( ray_end, w_end);
- vec2 vp_line_dir = vp_line_end-vp_line_begin;
-
- //we need to interpolate w along the ray, to generate perspective correct reflections
-
- w_begin = 1.0/w_begin;
- w_end = 1.0/w_end;
+ vec2 vp_line_end = view_to_screen(ray_end, w_end);
+ vec2 vp_line_dir = vp_line_end - vp_line_begin;
+ // we need to interpolate w along the ray, to generate perspective correct reflections
+ w_begin = 1.0 / w_begin;
+ w_end = 1.0 / w_end;
- float z_begin = vertex.z*w_begin;
- float z_end = ray_end.z*w_end;
+ float z_begin = vertex.z * w_begin;
+ float z_end = ray_end.z * w_end;
- vec2 line_begin = vp_line_begin/pixel_size;
- vec2 line_dir = vp_line_dir/pixel_size;
+ vec2 line_begin = vp_line_begin / pixel_size;
+ vec2 line_dir = vp_line_dir / pixel_size;
float z_dir = z_end - z_begin;
float w_dir = w_end - w_begin;
-
// clip the line to the viewport edges
float scale_max_x = min(1.0, 0.99 * (1.0 - vp_line_begin.x) / max(1e-5, vp_line_dir.x));
@@ -124,126 +112,114 @@ void main() {
float line_clip = min(scale_max_x, scale_max_y) * min(scale_min_x, scale_min_y);
line_dir *= line_clip;
z_dir *= line_clip;
- w_dir *=line_clip;
+ w_dir *= line_clip;
- //clip z and w advance to line advance
- vec2 line_advance = normalize(line_dir); //down to pixel
- float step_size = length(line_advance)/length(line_dir);
- float z_advance = z_dir*step_size; // adapt z advance to line advance
- float w_advance = w_dir*step_size; // adapt w advance to line advance
+ // clip z and w advance to line advance
+ vec2 line_advance = normalize(line_dir); // down to pixel
+ float step_size = length(line_advance) / length(line_dir);
+ float z_advance = z_dir * step_size; // adapt z advance to line advance
+ float w_advance = w_dir * step_size; // adapt w advance to line advance
- //make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice)
- float advance_angle_adj = 1.0/max(abs(line_advance.x),abs(line_advance.y));
- line_advance*=advance_angle_adj; // adapt z advance to line advance
- z_advance*=advance_angle_adj;
- w_advance*=advance_angle_adj;
+ // make line advance faster if direction is closer to pixel edges (this avoids sampling the same pixel twice)
+ float advance_angle_adj = 1.0 / max(abs(line_advance.x), abs(line_advance.y));
+ line_advance *= advance_angle_adj; // adapt z advance to line advance
+ z_advance *= advance_angle_adj;
+ w_advance *= advance_angle_adj;
vec2 pos = line_begin;
float z = z_begin;
float w = w_begin;
- float z_from=z/w;
- float z_to=z_from;
+ float z_from = z / w;
+ float z_to = z_from;
float depth;
- vec2 prev_pos=pos;
+ vec2 prev_pos = pos;
- bool found=false;
+ bool found = false;
- float steps_taken=0.0;
+ float steps_taken = 0.0;
- for(int i=0;i<num_steps;i++) {
+ for (int i = 0; i < num_steps; i++) {
- pos+=line_advance;
- z+=z_advance;
- w+=w_advance;
+ pos += line_advance;
+ z += z_advance;
+ w += w_advance;
- //convert to linear depth
+ // convert to linear depth
- depth = texture(source_depth, pos*pixel_size).r * 2.0 - 1.0;
+ depth = texture(source_depth, pos * pixel_size).r * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
#endif
- depth=-depth;
+ depth = -depth;
z_from = z_to;
- z_to = z/w;
+ z_to = z / w;
- if (depth>z_to) {
- //if depth was surpassed
- if (depth<=max(z_to,z_from)+depth_tolerance) {
- //check the depth tolerance
- found=true;
+ if (depth > z_to) {
+ // if depth was surpassed
+ if (depth <= max(z_to, z_from) + depth_tolerance) {
+ // check the depth tolerance
+ found = true;
}
break;
}
- steps_taken+=1.0;
- prev_pos=pos;
+ steps_taken += 1.0;
+ prev_pos = pos;
}
-
-
-
if (found) {
- float margin_blend=1.0;
+ float margin_blend = 1.0;
-
- vec2 margin = vec2((viewport_size.x+viewport_size.y)*0.5*0.05); //make a uniform margin
- if (any(bvec4(lessThan(pos,-margin),greaterThan(pos,viewport_size+margin)))) {
- //clip outside screen + margin
- frag_color=vec4(0.0);
+ vec2 margin = vec2((viewport_size.x + viewport_size.y) * 0.5 * 0.05); // make a uniform margin
+ if (any(bvec4(lessThan(pos, -margin), greaterThan(pos, viewport_size + margin)))) {
+ // clip outside screen + margin
+ frag_color = vec4(0.0);
return;
}
{
//blend fading out towards external margin
- vec2 margin_grad = mix(pos-viewport_size,-pos,lessThan(pos,vec2(0.0)));
- margin_blend = 1.0-smoothstep(0.0,margin.x,max(margin_grad.x,margin_grad.y));
- //margin_blend=1.0;
-
+ vec2 margin_grad = mix(pos - viewport_size, -pos, lessThan(pos, vec2(0.0)));
+ margin_blend = 1.0 - smoothstep(0.0, margin.x, max(margin_grad.x, margin_grad.y));
+ //margin_blend = 1.0;
}
vec2 final_pos;
float grad;
- grad=steps_taken/float(num_steps);
- float initial_fade = curve_fade_in==0.0 ? 1.0 : pow(clamp(grad,0.0,1.0),curve_fade_in);
- float fade = pow(clamp(1.0-grad,0.0,1.0),distance_fade)*initial_fade;
- final_pos=pos;
-
-
-
-
-
-
+ grad = steps_taken / float(num_steps);
+ float initial_fade = curve_fade_in == 0.0 ? 1.0 : pow(clamp(grad, 0.0, 1.0), curve_fade_in);
+ float fade = pow(clamp(1.0 - grad, 0.0, 1.0), distance_fade) * initial_fade;
+ final_pos = pos;
#ifdef REFLECT_ROUGHNESS
-
vec4 final_color;
- //if roughness is enabled, do screen space cone tracing
+ // if roughness is enabled, do screen space cone tracing
if (roughness > 0.001) {
///////////////////////////////////////////////////////////////////////////////////////
- //use a blurred version (in consecutive mipmaps) of the screen to simulate roughness
+ // use a blurred version (in consecutive mipmaps) of the screen to simulate roughness
- float gloss = 1.0-roughness;
+ float gloss = 1.0 - roughness;
float cone_angle = roughness * M_PI * 0.5;
vec2 cone_dir = final_pos - line_begin;
float cone_len = length(cone_dir);
- cone_dir = normalize(cone_dir); //will be used normalized from now on
+ cone_dir = normalize(cone_dir); // will be used normalized from now on
float max_mipmap = filter_mipmap_levels - 1.0;
- float gloss_mult=gloss;
+ float gloss_mult = gloss;
- float rem_alpha=1.0;
+ float rem_alpha = 1.0;
final_color = vec4(0.0);
- for(int i=0;i<7;i++) {
+ for (int i = 0; i < 7; i++) {
- float op_len = 2.0 * tan(cone_angle) * cone_len; //opposite side of iso triangle
+ float op_len = 2.0 * tan(cone_angle) * cone_len; // opposite side of iso triangle
float radius;
{
- //fit to sphere inside cone (sphere ends at end of cone), something like this:
+ // fit to sphere inside cone (sphere ends at end of cone), something like this:
// ___
// \O/
// V
@@ -257,31 +233,31 @@ void main() {
radius = (a * (sqrt(a2 + fh2) - a)) / (4.0f * h);
}
- //find the place where screen must be sampled
- vec2 sample_pos = ( line_begin + cone_dir * (cone_len - radius) ) * pixel_size;
- //radius is in pixels, so it's natural that log2(radius) maps to the right mipmap for the amount of pixels
- float mipmap = clamp( log2( radius ), 0.0, max_mipmap );
+ // find the place where screen must be sampled
+ vec2 sample_pos = (line_begin + cone_dir * (cone_len - radius)) * pixel_size;
+ // radius is in pixels, so it's natural that log2(radius) maps to the right mipmap for the amount of pixels
+ float mipmap = clamp(log2(radius), 0.0, max_mipmap);
+ //mipmap = max(mipmap - 1.0, 0.0);
- //mipmap = max(mipmap-1.0,0.0);
- //do sampling
+ // do sampling
vec4 sample_color;
{
- sample_color = textureLod(source_diffuse,sample_pos,mipmap);
+ sample_color = textureLod(source_diffuse, sample_pos, mipmap);
}
- //multiply by gloss
- sample_color.rgb*=gloss_mult;
- sample_color.a=gloss_mult;
+ // multiply by gloss
+ sample_color.rgb *= gloss_mult;
+ sample_color.a = gloss_mult;
rem_alpha -= sample_color.a;
- if(rem_alpha < 0.0) {
+ if (rem_alpha < 0.0) {
sample_color.rgb *= (1.0 - abs(rem_alpha));
}
- final_color+=sample_color;
+ final_color += sample_color;
- if (final_color.a>=0.95) {
+ if (final_color.a >= 0.95) {
// This code of accumulating gloss and aborting on near one
// makes sense when you think of cone tracing.
// Think of it as if roughness was 0, then we could abort on the first
@@ -290,29 +266,21 @@ void main() {
break;
}
- cone_len-=radius*2.0; //go to next (smaller) circle.
-
- gloss_mult*=gloss;
-
+ cone_len -= radius * 2.0; // go to next (smaller) circle.
+ gloss_mult *= gloss;
}
} else {
- final_color = textureLod(source_diffuse,final_pos*pixel_size,0.0);
+ final_color = textureLod(source_diffuse, final_pos * pixel_size, 0.0);
}
- frag_color = vec4(final_color.rgb,fade*margin_blend);
+ frag_color = vec4(final_color.rgb, fade * margin_blend);
#else
- frag_color = vec4(textureLod(source_diffuse,final_pos*pixel_size,0.0).rgb,fade*margin_blend);
+ frag_color = vec4(textureLod(source_diffuse, final_pos * pixel_size, 0.0).rgb, fade * margin_blend);
#endif
-
-
} else {
- frag_color = vec4(0.0,0.0,0.0,0.0);
+ frag_color = vec4(0.0, 0.0, 0.0, 0.0);
}
-
-
-
}
-
diff --git a/drivers/gles3/shaders/ssao.glsl b/drivers/gles3/shaders/ssao.glsl
index 219f0957e0..be44365169 100644
--- a/drivers/gles3/shaders/ssao.glsl
+++ b/drivers/gles3/shaders/ssao.glsl
@@ -1,34 +1,30 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
void main() {
gl_Position = vertex_attrib;
- gl_Position.z=1.0;
+ gl_Position.z = 1.0;
}
+/* clang-format off */
[fragment]
#define TWO_PI 6.283185307179586476925286766559
#ifdef SSAO_QUALITY_HIGH
-
#define NUM_SAMPLES (80)
-
#endif
#ifdef SSAO_QUALITY_LOW
-
#define NUM_SAMPLES (15)
-
#endif
#if !defined(SSAO_QUALITY_LOW) && !defined(SSAO_QUALITY_HIGH)
-
#define NUM_SAMPLES (40)
-
#endif
// If using depth mip levels, the log of the maximum pixel offset before we need to switch to a lower
@@ -43,19 +39,21 @@ void main() {
// This is the number of turns around the circle that the spiral pattern makes. This should be prime to prevent
// taps from lining up. This particular choice was tuned for NUM_SAMPLES == 9
-const int ROTATIONS[] = int[]( 1, 1, 2, 3, 2, 5, 2, 3, 2,
-3, 3, 5, 5, 3, 4, 7, 5, 5, 7,
-9, 8, 5, 5, 7, 7, 7, 8, 5, 8,
-11, 12, 7, 10, 13, 8, 11, 8, 7, 14,
-11, 11, 13, 12, 13, 19, 17, 13, 11, 18,
-19, 11, 11, 14, 17, 21, 15, 16, 17, 18,
-13, 17, 11, 17, 19, 18, 25, 18, 19, 19,
-29, 21, 19, 27, 31, 29, 21, 18, 17, 29,
-31, 31, 23, 18, 25, 26, 25, 23, 19, 34,
-19, 27, 21, 25, 39, 29, 17, 21, 27 );
+const int ROTATIONS[] = int[](
+ 1, 1, 2, 3, 2, 5, 2, 3, 2,
+ 3, 3, 5, 5, 3, 4, 7, 5, 5, 7,
+ 9, 8, 5, 5, 7, 7, 7, 8, 5, 8,
+ 11, 12, 7, 10, 13, 8, 11, 8, 7, 14,
+ 11, 11, 13, 12, 13, 19, 17, 13, 11, 18,
+ 19, 11, 11, 14, 17, 21, 15, 16, 17, 18,
+ 13, 17, 11, 17, 19, 18, 25, 18, 19, 19,
+ 29, 21, 19, 27, 31, 29, 21, 18, 17, 29,
+ 31, 31, 23, 18, 25, 26, 25, 23, 19, 34,
+ 19, 27, 21, 25, 39, 29, 17, 21, 27);
+/* clang-format on */
//#define NUM_SPIRAL_TURNS (7)
-const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES-1];
+const int NUM_SPIRAL_TURNS = ROTATIONS[NUM_SAMPLES - 1];
uniform sampler2D source_depth; //texunit:0
uniform highp usampler2D source_depth_mipmaps; //texunit:1
@@ -90,44 +88,41 @@ vec3 reconstructCSPosition(vec2 S, float z) {
}
vec3 getPosition(ivec2 ssP) {
- vec3 P;
- P.z = texelFetch(source_depth, ssP, 0).r;
+ vec3 P;
+ P.z = texelFetch(source_depth, ssP, 0).r;
- P.z = P.z * 2.0 - 1.0;
+ P.z = P.z * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- P.z = ((P.z + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ P.z = ((P.z + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
- P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
+ P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
#endif
- P.z = -P.z;
+ P.z = -P.z;
- // Offset to pixel center
- P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
- return P;
+ // Offset to pixel center
+ P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
+ return P;
}
/** Reconstructs screen-space unit normal from screen-space position */
vec3 reconstructCSFaceNormal(vec3 C) {
- return normalize(cross(dFdy(C), dFdx(C)));
+ return normalize(cross(dFdy(C), dFdx(C)));
}
-
-
/** Returns a unit vector and a screen-space radius for the tap on a unit disk (the caller should scale by the actual disk radius) */
-vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR){
- // Radius relative to ssR
- float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES));
- float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle;
+vec2 tapLocation(int sampleNumber, float spinAngle, out float ssR) {
+ // Radius relative to ssR
+ float alpha = (float(sampleNumber) + 0.5) * (1.0 / float(NUM_SAMPLES));
+ float angle = alpha * (float(NUM_SPIRAL_TURNS) * 6.28) + spinAngle;
- ssR = alpha;
- return vec2(cos(angle), sin(angle));
+ ssR = alpha;
+ return vec2(cos(angle), sin(angle));
}
-
/** Read the camera-space position of the point at screen-space pixel ssP + unitOffset * ssR. Assumes length(unitOffset) == 1 */
vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
- // Derivation:
- // mipLevel = floor(log(ssR / MAX_OFFSET));
+ // Derivation:
+ // mipLevel = floor(log(ssR / MAX_OFFSET));
int mipLevel = clamp(int(floor(log2(ssR))) - LOG_MAX_OFFSET, 0, MAX_MIP_LEVEL);
ivec2 ssP = ivec2(ssR * unitOffset) + ssC;
@@ -138,98 +133,91 @@ vec3 getOffsetPosition(ivec2 ssC, vec2 unitOffset, float ssR) {
// Manually clamp to the texture size because texelFetch bypasses the texture unit
ivec2 mipP = clamp(ssP >> mipLevel, ivec2(0), (screen_size >> mipLevel) - ivec2(1));
-
if (mipLevel < 1) {
//read from depth buffer
P.z = texelFetch(source_depth, mipP, 0).r;
P.z = P.z * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- P.z = ((P.z + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ P.z = ((P.z + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
P.z = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - P.z * (camera_z_far - camera_z_near));
-
#endif
P.z = -P.z;
} else {
//read from mipmaps
- uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel-1).r;
- P.z = -(float(d)/65535.0)*camera_z_far;
+ uint d = texelFetch(source_depth_mipmaps, mipP, mipLevel - 1).r;
+ P.z = -(float(d) / 65535.0) * camera_z_far;
}
-
// Offset to pixel center
P = reconstructCSPosition(vec2(ssP) + vec2(0.5), P.z);
return P;
}
-
-
/** Compute the occlusion due to sample with index \a i about the pixel at \a ssC that corresponds
- to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius
+ to camera-space point \a C with unit normal \a n_C, using maximum screen-space sampling radius \a ssDiskRadius
- Note that units of H() in the HPG12 paper are meters, not
- unitless. The whole falloff/sampling function is therefore
- unitless. In this implementation, we factor out (9 / radius).
+ Note that units of H() in the HPG12 paper are meters, not
+ unitless. The whole falloff/sampling function is therefore
+ unitless. In this implementation, we factor out (9 / radius).
- Four versions of the falloff function are implemented below
+ Four versions of the falloff function are implemented below
*/
-float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius,in float p_radius, in int tapIndex, in float randomPatternRotationAngle) {
- // Offset on the unit disk, spun for this pixel
- float ssR;
- vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
- ssR *= ssDiskRadius;
+float sampleAO(in ivec2 ssC, in vec3 C, in vec3 n_C, in float ssDiskRadius, in float p_radius, in int tapIndex, in float randomPatternRotationAngle) {
+ // Offset on the unit disk, spun for this pixel
+ float ssR;
+ vec2 unitOffset = tapLocation(tapIndex, randomPatternRotationAngle, ssR);
+ ssR *= ssDiskRadius;
- // The occluding point in camera space
- vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
+ // The occluding point in camera space
+ vec3 Q = getOffsetPosition(ssC, unitOffset, ssR);
- vec3 v = Q - C;
+ vec3 v = Q - C;
- float vv = dot(v, v);
- float vn = dot(v, n_C);
+ float vv = dot(v, v);
+ float vn = dot(v, n_C);
- const float epsilon = 0.01;
- float radius2 = p_radius*p_radius;
+ const float epsilon = 0.01;
+ float radius2 = p_radius * p_radius;
- // A: From the HPG12 paper
- // Note large epsilon to avoid overdarkening within cracks
- //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
+ // A: From the HPG12 paper
+ // Note large epsilon to avoid overdarkening within cracks
+ //return float(vv < radius2) * max((vn - bias) / (epsilon + vv), 0.0) * radius2 * 0.6;
- // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
- float f=max(radius2 - vv, 0.0);
- return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
+ // B: Smoother transition to zero (lowers contrast, smoothing out corners). [Recommended]
+ float f = max(radius2 - vv, 0.0);
+ return f * f * f * max((vn - bias) / (epsilon + vv), 0.0);
- // C: Medium contrast (which looks better at high radii), no division. Note that the
- // contribution still falls off with radius^2, but we've adjusted the rate in a way that is
- // more computationally efficient and happens to be aesthetically pleasing.
- // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
+ // C: Medium contrast (which looks better at high radii), no division. Note that the
+ // contribution still falls off with radius^2, but we've adjusted the rate in a way that is
+ // more computationally efficient and happens to be aesthetically pleasing.
+ // return 4.0 * max(1.0 - vv * invRadius2, 0.0) * max(vn - bias, 0.0);
- // D: Low contrast, no division operation
- // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
+ // D: Low contrast, no division operation
+ // return 2.0 * float(vv < radius * radius) * max(vn - bias, 0.0);
}
-
-
void main() {
-
-
// Pixel being shaded
ivec2 ssC = ivec2(gl_FragCoord.xy);
// World space point being shaded
vec3 C = getPosition(ssC);
-/* if (C.z <= -camera_z_far*0.999) {
- // We're on the skybox
- visibility=1.0;
- return;
- }*/
+ /*
+ if (C.z <= -camera_z_far * 0.999) {
+ // We're on the skybox
+ visibility=1.0;
+ return;
+ }
+ */
- //visibility=-C.z/camera_z_far;
+ //visibility = -C.z / camera_z_far;
//return;
#if 0
- vec3 n_C = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0;
+ vec3 n_C = texelFetch(source_normal, ssC, 0).rgb * 2.0 - 1.0;
#else
vec3 n_C = reconstructCSFaceNormal(C);
n_C = -n_C;
@@ -251,7 +239,7 @@ void main() {
#endif
float sum = 0.0;
for (int i = 0; i < NUM_SAMPLES; ++i) {
- sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius,i, randomPatternRotationAngle);
+ sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius, i, randomPatternRotationAngle);
}
float A = max(0.0, 1.0 - sum * intensity_div_r6 * (5.0 / float(NUM_SAMPLES)));
@@ -271,10 +259,10 @@ void main() {
sum = 0.0;
for (int i = 0; i < NUM_SAMPLES; ++i) {
- sum += sampleAO(ssC, C, n_C, ssDiskRadius,radius2, i, randomPatternRotationAngle);
+ sum += sampleAO(ssC, C, n_C, ssDiskRadius, radius2, i, randomPatternRotationAngle);
}
- A= min(A,max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / float(NUM_SAMPLES))));
+ A = min(A, max(0.0, 1.0 - sum * intensity_div_r62 * (5.0 / float(NUM_SAMPLES))));
#endif
// Bilateral box-filter over a quad for free, respecting depth edges
// (the difference that this makes is subtle)
@@ -286,8 +274,4 @@ void main() {
}
visibility = A;
-
}
-
-
-
diff --git a/drivers/gles3/shaders/ssao_blur.glsl b/drivers/gles3/shaders/ssao_blur.glsl
index 472dc21acf..c49ea1e957 100644
--- a/drivers/gles3/shaders/ssao_blur.glsl
+++ b/drivers/gles3/shaders/ssao_blur.glsl
@@ -1,26 +1,25 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
void main() {
gl_Position = vertex_attrib;
- gl_Position.z=1.0;
+ gl_Position.z = 1.0;
}
+/* clang-format off */
[fragment]
-
uniform sampler2D source_ssao; //texunit:0
+/* clang-format on */
uniform sampler2D source_depth; //texunit:1
uniform sampler2D source_normal; //texunit:3
-
layout(location = 0) out float visibility;
-
//////////////////////////////////////////////////////////////////////////////////////////////
// Tunable Parameters:
@@ -28,32 +27,30 @@ layout(location = 0) out float visibility;
uniform float edge_sharpness;
/** Step in 2-pixel intervals since we already blurred against neighbors in the
- first AO pass. This constant can be increased while R decreases to improve
- performance at the expense of some dithering artifacts.
+ first AO pass. This constant can be increased while R decreases to improve
+ performance at the expense of some dithering artifacts.
- Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was
- unobjectionable after shading was applied but eliminated most temporal incoherence
- from using small numbers of sample taps.
- */
+ Morgan found that a scale of 3 left a 1-pixel checkerboard grid that was
+ unobjectionable after shading was applied but eliminated most temporal incoherence
+ from using small numbers of sample taps.
+ */
uniform int filter_scale;
/** Filter radius in pixels. This will be multiplied by SCALE. */
-#define R (4)
-
+#define R (4)
//////////////////////////////////////////////////////////////////////////////////////////////
-
// Gaussian coefficients
const float gaussian[R + 1] =
-// float[](0.356642, 0.239400, 0.072410, 0.009869);
-// float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0
- float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0
-// float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0
+ //float[](0.356642, 0.239400, 0.072410, 0.009869);
+ //float[](0.398943, 0.241971, 0.053991, 0.004432, 0.000134); // stddev = 1.0
+ float[](0.153170, 0.144893, 0.122649, 0.092902, 0.062970); // stddev = 2.0
+//float[](0.111220, 0.107798, 0.098151, 0.083953, 0.067458, 0.050920, 0.036108); // stddev = 3.0
-/** (1, 0) or (0, 1)*/
-uniform ivec2 axis;
+/** (1, 0) or (0, 1) */
+uniform ivec2 axis;
uniform float camera_z_far;
uniform float camera_z_near;
@@ -65,18 +62,18 @@ void main() {
ivec2 ssC = ivec2(gl_FragCoord.xy);
float depth = texelFetch(source_depth, ssC, 0).r;
- //vec3 normal = texelFetch(source_normal,ssC,0).rgb * 2.0 - 1.0;
+ //vec3 normal = texelFetch(source_normal, ssC, 0).rgb * 2.0 - 1.0;
depth = depth * 2.0 - 1.0;
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
float depth_divide = 1.0 / camera_z_far;
-// depth*=depth_divide;
+ //depth *= depth_divide;
/*
- if (depth > camera_z_far*0.999) {
- discard;//skybox
+ if (depth > camera_z_far * 0.999) {
+ discard; //skybox
}
*/
@@ -96,23 +93,21 @@ void main() {
if (r != 0) {
ivec2 ppos = ssC + axis * (r * filter_scale);
- float value = texelFetch(source_ssao, clamp(ppos,ivec2(0),clamp_limit), 0).r;
- ivec2 rpos = clamp(ppos,ivec2(0),clamp_limit);
+ float value = texelFetch(source_ssao, clamp(ppos, ivec2(0), clamp_limit), 0).r;
+ ivec2 rpos = clamp(ppos, ivec2(0), clamp_limit);
float temp_depth = texelFetch(source_depth, rpos, 0).r;
//vec3 temp_normal = texelFetch(source_normal, rpos, 0).rgb * 2.0 - 1.0;
temp_depth = temp_depth * 2.0 - 1.0;
temp_depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - temp_depth * (camera_z_far - camera_z_near));
-// temp_depth *= depth_divide;
+ //temp_depth *= depth_divide;
// spatial domain: offset gaussian tap
float weight = 0.3 + gaussian[abs(r)];
- //weight *= max(0.0,dot(temp_normal,normal));
+ //weight *= max(0.0, dot(temp_normal, normal));
// range domain (the "bilateral" weight). As depth difference increases, decrease weight.
- weight *= max(0.0, 1.0
- - edge_sharpness * abs(temp_depth - depth)
- );
+ weight *= max(0.0, 1.0 - edge_sharpness * abs(temp_depth - depth));
sum += value * weight;
totalWeight += weight;
diff --git a/drivers/gles3/shaders/ssao_minify.glsl b/drivers/gles3/shaders/ssao_minify.glsl
index 647c762438..1696648dae 100644
--- a/drivers/gles3/shaders/ssao_minify.glsl
+++ b/drivers/gles3/shaders/ssao_minify.glsl
@@ -1,20 +1,22 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
void main() {
gl_Position = vertex_attrib;
}
+/* clang-format off */
[fragment]
-
#ifdef MINIFY_START
#define SDEPTH_TYPE highp sampler2D
uniform float camera_z_far;
+/* clang-format on */
uniform float camera_z_near;
#else
@@ -32,28 +34,23 @@ layout(location = 0) out mediump uint depth;
void main() {
-
ivec2 ssP = ivec2(gl_FragCoord.xy);
- // Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling.
- // On DX9, the bit-and can be implemented with floating-point modulo
+ // Rotated grid subsampling to avoid XY directional bias or Z precision bias while downsampling.
+ // On DX9, the bit-and can be implemented with floating-point modulo
#ifdef MINIFY_START
float fdepth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r;
fdepth = fdepth * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- fdepth = ((fdepth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ fdepth = ((fdepth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
fdepth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - fdepth * (camera_z_far - camera_z_near));
#endif
fdepth /= camera_z_far;
- depth = uint(clamp(fdepth*65535.0,0.0,65535.0));
+ depth = uint(clamp(fdepth * 65535.0, 0.0, 65535.0));
#else
depth = texelFetch(source_depth, clamp(ssP * 2 + ivec2(ssP.y & 1, ssP.x & 1), ivec2(0), from_size - ivec2(1)), source_mipmap).r;
#endif
-
-
}
-
-
diff --git a/drivers/gles3/shaders/subsurf_scattering.glsl b/drivers/gles3/shaders/subsurf_scattering.glsl
index fc66d66198..f40fb3a244 100644
--- a/drivers/gles3/shaders/subsurf_scattering.glsl
+++ b/drivers/gles3/shaders/subsurf_scattering.glsl
@@ -1,105 +1,93 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
-
void main() {
uv_interp = uv_in;
gl_Position = vertex_attrib;
}
+/* clang-format off */
[fragment]
//#define QUALIFIER uniform // some guy on the interweb says it may be faster with this
#define QUALIFIER const
#ifdef USE_25_SAMPLES
-
-const int kernel_size=25;
-QUALIFIER vec2 kernel[25] = vec2[] (
- vec2(0.530605, 0.0),
- vec2(0.000973794, -3.0),
- vec2(0.00333804, -2.52083),
- vec2(0.00500364, -2.08333),
- vec2(0.00700976, -1.6875),
- vec2(0.0094389, -1.33333),
- vec2(0.0128496, -1.02083),
- vec2(0.017924, -0.75),
- vec2(0.0263642, -0.520833),
- vec2(0.0410172, -0.333333),
- vec2(0.0493588, -0.1875),
- vec2(0.0402784, -0.0833333),
- vec2(0.0211412, -0.0208333),
- vec2(0.0211412, 0.0208333),
- vec2(0.0402784, 0.0833333),
- vec2(0.0493588, 0.1875),
- vec2(0.0410172, 0.333333),
- vec2(0.0263642, 0.520833),
- vec2(0.017924, 0.75),
- vec2(0.0128496, 1.02083),
- vec2(0.0094389, 1.33333),
- vec2(0.00700976, 1.6875),
- vec2(0.00500364, 2.08333),
- vec2(0.00333804, 2.52083),
- vec2(0.000973794, 3.0)
-);
-
+const int kernel_size = 25;
+/* clang-format on */
+QUALIFIER vec2 kernel[25] = vec2[](
+ vec2(0.530605, 0.0),
+ vec2(0.000973794, -3.0),
+ vec2(0.00333804, -2.52083),
+ vec2(0.00500364, -2.08333),
+ vec2(0.00700976, -1.6875),
+ vec2(0.0094389, -1.33333),
+ vec2(0.0128496, -1.02083),
+ vec2(0.017924, -0.75),
+ vec2(0.0263642, -0.520833),
+ vec2(0.0410172, -0.333333),
+ vec2(0.0493588, -0.1875),
+ vec2(0.0402784, -0.0833333),
+ vec2(0.0211412, -0.0208333),
+ vec2(0.0211412, 0.0208333),
+ vec2(0.0402784, 0.0833333),
+ vec2(0.0493588, 0.1875),
+ vec2(0.0410172, 0.333333),
+ vec2(0.0263642, 0.520833),
+ vec2(0.017924, 0.75),
+ vec2(0.0128496, 1.02083),
+ vec2(0.0094389, 1.33333),
+ vec2(0.00700976, 1.6875),
+ vec2(0.00500364, 2.08333),
+ vec2(0.00333804, 2.52083),
+ vec2(0.000973794, 3.0));
#endif //USE_25_SAMPLES
#ifdef USE_17_SAMPLES
-
-const int kernel_size=17;
-
+const int kernel_size = 17;
QUALIFIER vec2 kernel[17] = vec2[](
- vec2(0.536343, 0.0),
- vec2(0.00317394, -2.0),
- vec2(0.0100386, -1.53125),
- vec2(0.0144609, -1.125),
- vec2(0.0216301, -0.78125),
- vec2(0.0347317, -0.5),
- vec2(0.0571056, -0.28125),
- vec2(0.0582416, -0.125),
- vec2(0.0324462, -0.03125),
- vec2(0.0324462, 0.03125),
- vec2(0.0582416, 0.125),
- vec2(0.0571056, 0.28125),
- vec2(0.0347317, 0.5),
- vec2(0.0216301, 0.78125),
- vec2(0.0144609, 1.125),
- vec2(0.0100386, 1.53125),
- vec2(0.00317394,2.0)
-);
-
+ vec2(0.536343, 0.0),
+ vec2(0.00317394, -2.0),
+ vec2(0.0100386, -1.53125),
+ vec2(0.0144609, -1.125),
+ vec2(0.0216301, -0.78125),
+ vec2(0.0347317, -0.5),
+ vec2(0.0571056, -0.28125),
+ vec2(0.0582416, -0.125),
+ vec2(0.0324462, -0.03125),
+ vec2(0.0324462, 0.03125),
+ vec2(0.0582416, 0.125),
+ vec2(0.0571056, 0.28125),
+ vec2(0.0347317, 0.5),
+ vec2(0.0216301, 0.78125),
+ vec2(0.0144609, 1.125),
+ vec2(0.0100386, 1.53125),
+ vec2(0.00317394, 2.0));
#endif //USE_17_SAMPLES
-
#ifdef USE_11_SAMPLES
-
-const int kernel_size=11;
-
+const int kernel_size = 11;
QUALIFIER vec2 kernel[11] = vec2[](
- vec2(0.560479, 0.0),
- vec2(0.00471691, -2.0),
- vec2(0.0192831, -1.28),
- vec2(0.03639, -0.72),
- vec2(0.0821904, -0.32),
- vec2(0.0771802, -0.08),
- vec2(0.0771802, 0.08),
- vec2(0.0821904, 0.32),
- vec2(0.03639, 0.72),
- vec2(0.0192831, 1.28),
- vec2(0.00471691,2.0)
-);
-
+ vec2(0.560479, 0.0),
+ vec2(0.00471691, -2.0),
+ vec2(0.0192831, -1.28),
+ vec2(0.03639, -0.72),
+ vec2(0.0821904, -0.32),
+ vec2(0.0771802, -0.08),
+ vec2(0.0771802, 0.08),
+ vec2(0.0821904, 0.32),
+ vec2(0.03639, 0.72),
+ vec2(0.0192831, 1.28),
+ vec2(0.00471691, 2.0));
#endif //USE_11_SAMPLES
-
-
uniform float max_radius;
uniform float camera_z_far;
uniform float camera_z_near;
@@ -115,28 +103,24 @@ layout(location = 0) out vec4 frag_color;
void main() {
- float strength = texture(source_sss,uv_interp).r;
- strength*=strength; //stored as sqrt
+ float strength = texture(source_sss, uv_interp).r;
+ strength *= strength; //stored as sqrt
// Fetch color of current pixel:
vec4 base_color = texture(source_diffuse, uv_interp);
-
- if (strength>0.0) {
-
+ if (strength > 0.0) {
// Fetch linear depth of current pixel:
float depth = texture(source_depth, uv_interp).r * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- depth = ((depth + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ depth = ((depth + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
float scale = unit_size; //remember depth is negative by default in OpenGL
#else
depth = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth * (camera_z_far - camera_z_near));
float scale = unit_size / depth; //remember depth is negative by default in OpenGL
#endif
-
-
// Calculate the final step to fetch the surrounding pixels:
vec2 step = max_radius * scale * dir;
step *= strength; // Modulate it using the alpha channel.
@@ -157,35 +141,33 @@ void main() {
#ifdef ENABLE_FOLLOW_SURFACE
// If the difference in depth is huge, we lerp color back to "colorM":
- float depth_cmp = texture(source_depth, offset).r *2.0 - 1.0;
+ float depth_cmp = texture(source_depth, offset).r * 2.0 - 1.0;
#ifdef USE_ORTHOGONAL_PROJECTION
- depth_cmp = ((depth_cmp + (camera_z_far + camera_z_near)/(camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near))/2.0;
+ depth_cmp = ((depth_cmp + (camera_z_far + camera_z_near) / (camera_z_far - camera_z_near)) * (camera_z_far - camera_z_near)) / 2.0;
#else
depth_cmp = 2.0 * camera_z_near * camera_z_far / (camera_z_far + camera_z_near - depth_cmp * (camera_z_far - camera_z_near));
#endif
- float s = clamp(300.0f * scale *
- max_radius * abs(depth - depth_cmp),0.0,1.0);
+ float s = clamp(300.0f * scale * max_radius * abs(depth - depth_cmp), 0.0, 1.0);
color = mix(color, base_color.rgb, s);
#endif
// Accumulate:
- color*=kernel[i].x;
+ color *= kernel[i].x;
#ifdef ENABLE_STRENGTH_WEIGHTING
float color_s = texture(source_sss, offset).r;
- color_weight+=color_s * kernel[i].x;
- color*=color_s;
+ color_weight += color_s * kernel[i].x;
+ color *= color_s;
#endif
color_accum += color;
-
}
#ifdef ENABLE_STRENGTH_WEIGHTING
- color_accum/=color_weight;
+ color_accum /= color_weight;
#endif
- frag_color = vec4(color_accum,base_color.a); //keep alpha (used for SSAO)
+ frag_color = vec4(color_accum, base_color.a); //keep alpha (used for SSAO)
} else {
frag_color = base_color;
}
diff --git a/drivers/gles3/shaders/tonemap.glsl b/drivers/gles3/shaders/tonemap.glsl
index a75871f08e..e4aa8d5730 100644
--- a/drivers/gles3/shaders/tonemap.glsl
+++ b/drivers/gles3/shaders/tonemap.glsl
@@ -1,27 +1,29 @@
+/* clang-format off */
[vertex]
-
-layout(location=0) in highp vec4 vertex_attrib;
-layout(location=4) in vec2 uv_in;
+layout(location = 0) in highp vec4 vertex_attrib;
+/* clang-format on */
+layout(location = 4) in vec2 uv_in;
out vec2 uv_interp;
void main() {
-
gl_Position = vertex_attrib;
+
uv_interp = uv_in;
+
#ifdef V_FLIP
- uv_interp.y = 1.0-uv_interp.y;
+ uv_interp.y = 1.0f - uv_interp.y;
#endif
-
}
+/* clang-format off */
[fragment]
#if !defined(GLES_OVER_GL)
precision mediump float;
#endif
-
+/* clang-format on */
in vec2 uv_interp;
@@ -31,89 +33,74 @@ uniform float exposure;
uniform float white;
#ifdef USE_AUTO_EXPOSURE
-
uniform highp sampler2D source_auto_exposure; //texunit:1
uniform highp float auto_exposure_grey;
-
#endif
#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
+#define USING_GLOW // only use glow when at least one glow level is selected
uniform highp sampler2D source_glow; //texunit:2
uniform highp float glow_intensity;
-
#endif
#ifdef USE_BCS
-
uniform vec3 bcs;
-
#endif
#ifdef USE_COLOR_CORRECTION
-
uniform sampler2D color_correction; //texunit:3
-
#endif
-
layout(location = 0) out vec4 frag_color;
#ifdef USE_GLOW_FILTER_BICUBIC
-
// w0, w1, w2, and w3 are the four cubic B-spline basis functions
-float w0(float a)
-{
- return (1.0/6.0)*(a*(a*(-a + 3.0) - 3.0) + 1.0);
+float w0(float a) {
+ return (1.0f / 6.0f) * (a * (a * (-a + 3.0f) - 3.0f) + 1.0f);
}
-float w1(float a)
-{
- return (1.0/6.0)*(a*a*(3.0*a - 6.0) + 4.0);
+float w1(float a) {
+ return (1.0f / 6.0f) * (a * a * (3.0f * a - 6.0f) + 4.0f);
}
-float w2(float a)
-{
- return (1.0/6.0)*(a*(a*(-3.0*a + 3.0) + 3.0) + 1.0);
+float w2(float a) {
+ return (1.0f / 6.0f) * (a * (a * (-3.0f * a + 3.0f) + 3.0f) + 1.0f);
}
-float w3(float a)
-{
- return (1.0/6.0)*(a*a*a);
+float w3(float a) {
+ return (1.0f / 6.0f) * (a * a * a);
}
// g0 and g1 are the two amplitude functions
-float g0(float a)
-{
- return w0(a) + w1(a);
+float g0(float a) {
+ return w0(a) + w1(a);
}
-float g1(float a)
-{
- return w2(a) + w3(a);
+float g1(float a) {
+ return w2(a) + w3(a);
}
// h0 and h1 are the two offset functions
-float h0(float a)
-{
- return -1.0 + w1(a) / (w0(a) + w1(a));
+float h0(float a) {
+ return -1.0f + w1(a) / (w0(a) + w1(a));
}
-float h1(float a)
-{
- return 1.0 + w3(a) / (w2(a) + w3(a));
+float h1(float a) {
+ return 1.0f + w3(a) / (w2(a) + w3(a));
}
uniform ivec2 glow_texture_size;
-vec4 texture2D_bicubic(sampler2D tex, vec2 uv,int p_lod)
-{
- float lod=float(p_lod);
+vec4 texture2D_bicubic(sampler2D tex, vec2 uv, int p_lod) {
+ float lod = float(p_lod);
vec2 tex_size = vec2(glow_texture_size >> p_lod);
- vec2 pixel_size =1.0/tex_size;
- uv = uv*tex_size + 0.5;
- vec2 iuv = floor( uv );
- vec2 fuv = fract( uv );
+ vec2 pixel_size = vec2(1.0f) / tex_size;
+
+ uv = uv * tex_size + vec2(0.5f);
+
+ vec2 iuv = floor(uv);
+ vec2 fuv = fract(uv);
float g0x = g0(fuv.x);
float g1x = g1(fuv.x);
@@ -122,206 +109,189 @@ vec4 texture2D_bicubic(sampler2D tex, vec2 uv,int p_lod)
float h0y = h0(fuv.y);
float h1y = h1(fuv.y);
- vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - 0.5) * pixel_size;
- vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - 0.5) * pixel_size;
- vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - 0.5) * pixel_size;
- vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - 0.5) * pixel_size;
+ vec2 p0 = (vec2(iuv.x + h0x, iuv.y + h0y) - vec2(0.5f)) * pixel_size;
+ vec2 p1 = (vec2(iuv.x + h1x, iuv.y + h0y) - vec2(0.5f)) * pixel_size;
+ vec2 p2 = (vec2(iuv.x + h0x, iuv.y + h1y) - vec2(0.5f)) * pixel_size;
+ vec2 p3 = (vec2(iuv.x + h1x, iuv.y + h1y) - vec2(0.5f)) * pixel_size;
- return g0(fuv.y) * (g0x * textureLod(tex, p0,lod) +
- g1x * textureLod(tex, p1,lod)) +
- g1(fuv.y) * (g0x * textureLod(tex, p2,lod) +
- g1x * textureLod(tex, p3,lod));
+ return (g0(fuv.y) * (g0x * textureLod(tex, p0, lod) + g1x * textureLod(tex, p1, lod))) +
+ (g1(fuv.y) * (g0x * textureLod(tex, p2, lod) + g1x * textureLod(tex, p3, lod)));
}
-
-
-#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) texture2D_bicubic(m_tex,m_uv,m_lod)
-
+#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) texture2D_bicubic(m_tex, m_uv, m_lod)
#else
-
-#define GLOW_TEXTURE_SAMPLE(m_tex,m_uv,m_lod) textureLod(m_tex,m_uv,float(m_lod))
-
+#define GLOW_TEXTURE_SAMPLE(m_tex, m_uv, m_lod) textureLod(m_tex, m_uv, float(m_lod))
#endif
+vec3 tonemap_filmic(vec3 color, float white) {
+ const float A = 0.15f;
+ const float B = 0.50f;
+ const float C = 0.10f;
+ const float D = 0.20f;
+ const float E = 0.02f;
+ const float F = 0.30f;
+ const float W = 11.2f;
-vec3 tonemap_filmic(vec3 color,float white) {
+ 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;
- float A = 0.15;
- float B = 0.50;
- float C = 0.10;
- float D = 0.20;
- float E = 0.02;
- float F = 0.30;
- float W = 11.2;
+ return clamp(color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f));
+}
- vec3 coltn = ((color*(A*color+C*B)+D*E)/(color*(A*color+B)+D*F))-E/F;
- float whitetn = ((white*(A*white+C*B)+D*E)/(white*(A*white+B)+D*F))-E/F;
+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 E = 0.14f;
- return coltn/whitetn;
+ vec3 color_tonemapped = (color * (A * color + B)) / (color * (C * color + D) + E);
+ float white_tonemapped = (white * (A * white + B)) / (white * (C * white + D) + E);
+ return clamp(color_tonemapped / white_tonemapped, vec3(0.0f), vec3(1.0f));
}
-vec3 tonemap_aces(vec3 color) {
- float a = 2.51f;
- float b = 0.03f;
- float c = 2.43f;
- float d = 0.59f;
- float e = 0.14f;
- return color = clamp((color*(a*color+b))/(color*(c*color+d)+e),vec3(0.0),vec3(1.0));
+vec3 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_reindhart(vec3 color,float white) {
-
- return ( color * ( 1.0 + ( color / ( white) ) ) ) / ( 1.0 + color );
+vec3 linear_to_srgb(vec3 color) { // convert linear rgb to srgb, assumes clamped input in range [0;1]
+ const vec3 a = vec3(0.055f);
+ return mix((vec3(1.0f) + a) * pow(color.rgb, vec3(1.0f / 2.4f)) - a, 12.92f * color.rgb, lessThan(color.rgb, vec3(0.0031308f)));
}
-void main() {
-
- vec4 color = textureLod(source, uv_interp, 0.0);
-
-#ifdef USE_AUTO_EXPOSURE
-
- color/=texelFetch(source_auto_exposure,ivec2(0,0),0).r/auto_exposure_grey;
+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);
#endif
- color*=exposure;
+#ifdef USE_FILMIC_TONEMAPPER
+ return tonemap_filmic(color, white);
+#endif
-#if defined(USE_GLOW_LEVEL1) || defined(USE_GLOW_LEVEL2) || defined(USE_GLOW_LEVEL3) || defined(USE_GLOW_LEVEL4) || defined(USE_GLOW_LEVEL5) || defined(USE_GLOW_LEVEL6) || defined(USE_GLOW_LEVEL7)
-#define USING_GLOW
+#ifdef USE_ACES_TONEMAPPER
+ return tonemap_aces(color, white);
#endif
-#if defined(USING_GLOW)
- vec3 glow = vec3(0.0);
+ return clamp(color, vec3(0.0f), vec3(1.0f)); // no other seleced -> linear
+}
-#ifdef USE_GLOW_LEVEL1
+vec3 gather_glow(sampler2D tex, vec2 uv) { // sample all selected glow levels
+ vec3 glow = vec3(0.0f);
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,1).rgb;
+#ifdef USE_GLOW_LEVEL1
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 1).rgb;
#endif
#ifdef USE_GLOW_LEVEL2
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,2).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 2).rgb;
#endif
#ifdef USE_GLOW_LEVEL3
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,3).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 3).rgb;
#endif
#ifdef USE_GLOW_LEVEL4
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,4).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 4).rgb;
#endif
#ifdef USE_GLOW_LEVEL5
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,5).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 5).rgb;
#endif
#ifdef USE_GLOW_LEVEL6
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,6).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 6).rgb;
#endif
#ifdef USE_GLOW_LEVEL7
- glow+=GLOW_TEXTURE_SAMPLE(source_glow,uv_interp,7).rgb;
+ glow += GLOW_TEXTURE_SAMPLE(tex, uv, 7).rgb;
#endif
+ return glow;
+}
- glow *= glow_intensity;
-
+vec3 apply_glow(vec3 color, vec3 glow) { // apply glow using the selected blending mode
+#ifdef USE_GLOW_REPLACE
+ color = glow;
#endif
-
-#ifdef USE_REINDHART_TONEMAPPER
-
- color.rgb = tonemap_reindhart(color.rgb,white);
-
-# if defined(USING_GLOW)
- glow = tonemap_reindhart(glow,white);
-# endif
-
+#ifdef USE_GLOW_SCREEN
+ color = max((color + glow) - (color * glow), vec3(0.0));
#endif
-#ifdef USE_FILMIC_TONEMAPPER
-
- color.rgb = tonemap_filmic(color.rgb,white);
-
-# if defined(USING_GLOW)
- glow = tonemap_filmic(glow,white);
-# endif
+#ifdef USE_GLOW_SOFTLIGHT
+ glow = glow * vec3(0.5f) + vec3(0.5f);
+ color.r = (glow.r <= 0.5f) ? (color.r - (1.0f - 2.0f * glow.r) * color.r * (1.0f - color.r)) : (((glow.r > 0.5f) && (color.r <= 0.25f)) ? (color.r + (2.0f * glow.r - 1.0f) * (4.0f * color.r * (4.0f * color.r + 1.0f) * (color.r - 1.0f) + 7.0f * color.r)) : (color.r + (2.0f * glow.r - 1.0f) * (sqrt(color.r) - color.r)));
+ color.g = (glow.g <= 0.5f) ? (color.g - (1.0f - 2.0f * glow.g) * color.g * (1.0f - color.g)) : (((glow.g > 0.5f) && (color.g <= 0.25f)) ? (color.g + (2.0f * glow.g - 1.0f) * (4.0f * color.g * (4.0f * color.g + 1.0f) * (color.g - 1.0f) + 7.0f * color.g)) : (color.g + (2.0f * glow.g - 1.0f) * (sqrt(color.g) - color.g)));
+ color.b = (glow.b <= 0.5f) ? (color.b - (1.0f - 2.0f * glow.b) * color.b * (1.0f - color.b)) : (((glow.b > 0.5f) && (color.b <= 0.25f)) ? (color.b + (2.0f * glow.b - 1.0f) * (4.0f * color.b * (4.0f * color.b + 1.0f) * (color.b - 1.0f) + 7.0f * color.b)) : (color.b + (2.0f * glow.b - 1.0f) * (sqrt(color.b) - color.b)));
#endif
-#ifdef USE_ACES_TONEMAPPER
-
- color.rgb = tonemap_aces(color.rgb);
-
-# if defined(USING_GLOW)
- glow = tonemap_aces(glow);
-# endif
-
+#if !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE) // no other selected -> additive
+ color += glow;
#endif
-#ifdef KEEP_3D_LINEAR
- // leave color as is...
-#else
- //regular Linear -> SRGB conversion
- vec3 a = vec3(0.055);
- color.rgb = mix( (vec3(1.0)+a)*pow(color.rgb,vec3(1.0/2.4))-a , 12.92*color.rgb , lessThan(color.rgb,vec3(0.0031308)));
-#endif
+ return color;
+}
-#if defined(USING_GLOW)
- glow = mix( (vec3(1.0)+a)*pow(glow,vec3(1.0/2.4))-a , 12.92*glow , lessThan(glow,vec3(0.0031308)));
-#endif
+vec3 apply_bcs(vec3 color, vec3 bcs) {
+ color = mix(vec3(0.0f), color, bcs.x);
+ color = mix(vec3(0.5f), color, bcs.y);
+ color = mix(vec3(dot(vec3(1.0f), color) * 0.33333f), color, bcs.z);
-//glow needs to be added in SRGB space (together with image space effects)
+ return color;
+}
- color.rgb = clamp(color.rgb,0.0,1.0);
+vec3 apply_color_correction(vec3 color, sampler2D correction_tex) {
+ color.r = texture(correction_tex, vec2(color.r, 0.0f)).r;
+ color.g = texture(correction_tex, vec2(color.g, 0.0f)).g;
+ color.b = texture(correction_tex, vec2(color.b, 0.0f)).b;
-#if defined(USING_GLOW)
- glow = clamp(glow,0.0,1.0);
-#endif
+ return color;
+}
-#ifdef USE_GLOW_REPLACE
+void main() {
+ vec3 color = textureLod(source, uv_interp, 0.0f).rgb;
- color.rgb = glow;
+ // Exposure
+#ifdef USE_AUTO_EXPOSURE
+ color /= texelFetch(source_auto_exposure, ivec2(0, 0), 0).r / auto_exposure_grey;
#endif
-#ifdef USE_GLOW_SCREEN
+ color *= exposure;
- color.rgb = max((color.rgb + glow) - (color.rgb * glow), vec3(0.0));
+ // Early Tonemap & SRGB Conversion
+ color = apply_tonemapping(color, white);
+
+#ifdef KEEP_3D_LINEAR
+ // leave color as is (-> don't convert to SRGB)
+#else
+ color = linear_to_srgb(color); // regular linear -> SRGB conversion
#endif
-#ifdef USE_GLOW_SOFTLIGHT
+ // Glow
- {
+#ifdef USING_GLOW
+ vec3 glow = gather_glow(source_glow, uv_interp) * glow_intensity;
- glow = (glow * 0.5) + 0.5;
- color.r = (glow.r <= 0.5) ? (color.r - (1.0 - 2.0 * glow.r) * color.r * (1.0 - color.r)) : (((glow.r > 0.5) && (color.r <= 0.25)) ? (color.r + (2.0 * glow.r - 1.0) * (4.0 * color.r * (4.0 * color.r + 1.0) * (color.r - 1.0) + 7.0 * color.r)) : (color.r + (2.0 * glow.r - 1.0) * (sqrt(color.r) - color.r)));
- color.g = (glow.g <= 0.5) ? (color.g - (1.0 - 2.0 * glow.g) * color.g * (1.0 - color.g)) : (((glow.g > 0.5) && (color.g <= 0.25)) ? (color.g + (2.0 * glow.g - 1.0) * (4.0 * color.g * (4.0 * color.g + 1.0) * (color.g - 1.0) + 7.0 * color.g)) : (color.g + (2.0 * glow.g - 1.0) * (sqrt(color.g) - color.g)));
- color.b = (glow.b <= 0.5) ? (color.b - (1.0 - 2.0 * glow.b) * color.b * (1.0 - color.b)) : (((glow.b > 0.5) && (color.b <= 0.25)) ? (color.b + (2.0 * glow.b - 1.0) * (4.0 * color.b * (4.0 * color.b + 1.0) * (color.b - 1.0) + 7.0 * color.b)) : (color.b + (2.0 * glow.b - 1.0) * (sqrt(color.b) - color.b)));
- }
+ // high dynamic range -> SRGB
+ glow = apply_tonemapping(glow, white);
+ glow = linear_to_srgb(glow);
+ color = apply_glow(color, glow);
#endif
-#if defined(USING_GLOW) && !defined(USE_GLOW_SCREEN) && !defined(USE_GLOW_SOFTLIGHT) && !defined(USE_GLOW_REPLACE)
- //additive
- color.rgb+=glow;
-#endif
+ // Additional effects
#ifdef USE_BCS
-
- color.rgb = mix(vec3(0.0),color.rgb,bcs.x);
- color.rgb = mix(vec3(0.5),color.rgb,bcs.y);
- color.rgb = mix(vec3(dot(vec3(1.0),color.rgb)*0.33333),color.rgb,bcs.z);
-
+ color = apply_bcs(color, bcs);
#endif
#ifdef USE_COLOR_CORRECTION
-
- color.r = texture(color_correction,vec2(color.r,0.0)).r;
- color.g = texture(color_correction,vec2(color.g,0.0)).g;
- color.b = texture(color_correction,vec2(color.b,0.0)).b;
+ color = apply_color_correction(color, color_correction);
#endif
-
- frag_color=vec4(color.rgb,1.0);
+ frag_color = vec4(color, 1.0f);
}
diff --git a/drivers/png/image_loader_png.cpp b/drivers/png/image_loader_png.cpp
index 3f512af8d5..b08688892e 100644
--- a/drivers/png/image_loader_png.cpp
+++ b/drivers/png/image_loader_png.cpp
@@ -271,7 +271,6 @@ static void _write_png_data(png_structp png_ptr, png_bytep data, png_size_t p_le
v.resize(vs + p_length);
PoolVector<uint8_t>::Write w = v.write();
copymem(&w[vs], data, p_length);
- //print_line("png write: "+itos(p_length));
}
static PoolVector<uint8_t> _lossless_pack_png(const Ref<Image> &p_image) {
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 0f47949b4b..744b3a35e6 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -64,18 +64,32 @@ void AudioDriverPulseAudio::pa_sink_info_cb(pa_context *c, const pa_sink_info *l
ad->pa_status++;
}
+void AudioDriverPulseAudio::pa_source_info_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) {
+ AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+
+ // If eol is set to a positive number, you're at the end of the list
+ if (eol > 0) {
+ return;
+ }
+
+ ad->pa_rec_map = l->channel_map;
+ ad->pa_status++;
+}
+
void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) {
AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+ ad->capture_default_device = i->default_source_name;
ad->default_device = i->default_sink_name;
ad->pa_status++;
}
-void AudioDriverPulseAudio::detect_channels() {
+void AudioDriverPulseAudio::detect_channels(bool capture) {
- pa_channel_map_init_stereo(&pa_map);
+ pa_channel_map_init_stereo(capture ? &pa_rec_map : &pa_map);
- if (device_name == "Default") {
+ String device = capture ? capture_device_name : device_name;
+ if (device == "Default") {
// Get the default output device name
pa_status = 0;
pa_operation *pa_op = pa_context_get_server_info(pa_ctx, &AudioDriverPulseAudio::pa_server_info_cb, (void *)this);
@@ -93,16 +107,22 @@ void AudioDriverPulseAudio::detect_channels() {
}
}
- char device[1024];
- if (device_name == "Default") {
- strcpy(device, default_device.utf8().get_data());
+ char dev[1024];
+ if (device == "Default") {
+ strcpy(dev, capture ? capture_default_device.utf8().get_data() : default_device.utf8().get_data());
} else {
- strcpy(device, device_name.utf8().get_data());
+ strcpy(dev, device.utf8().get_data());
}
// Now using the device name get the amount of channels
pa_status = 0;
- pa_operation *pa_op = pa_context_get_sink_info_by_name(pa_ctx, device, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this);
+ pa_operation *pa_op;
+ if (capture) {
+ pa_op = pa_context_get_source_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_source_info_cb, (void *)this);
+ } else {
+ pa_op = pa_context_get_sink_info_by_name(pa_ctx, dev, &AudioDriverPulseAudio::pa_sink_info_cb, (void *)this);
+ }
+
if (pa_op) {
while (pa_status == 0) {
int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
@@ -113,7 +133,11 @@ void AudioDriverPulseAudio::detect_channels() {
pa_operation_unref(pa_op);
} else {
- ERR_PRINT("pa_context_get_sink_info_by_name error");
+ if (capture) {
+ ERR_PRINT("pa_context_get_source_info_by_name error");
+ } else {
+ ERR_PRINT("pa_context_get_sink_info_by_name error");
+ }
}
}
@@ -155,14 +179,12 @@ Error AudioDriverPulseAudio::init_device() {
break;
}
- int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
+ int latency = GLOBAL_DEF_RST("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
pa_buffer_size = buffer_frames * pa_map.channels;
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("PulseAudio: detected " + itos(pa_map.channels) + " channels");
- print_line("PulseAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
- }
+ print_verbose("PulseAudio: detected " + itos(pa_map.channels) + " channels");
+ print_verbose("PulseAudio: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
pa_sample_spec spec;
spec.format = PA_SAMPLE_S16LE;
@@ -195,6 +217,10 @@ Error AudioDriverPulseAudio::init_device() {
samples_in.resize(buffer_frames * channels);
samples_out.resize(pa_buffer_size);
+ // Reset audio input to keep synchronisation.
+ input_position = 0;
+ input_size = 0;
+
return OK;
}
@@ -204,7 +230,7 @@ Error AudioDriverPulseAudio::init() {
thread_exited = false;
exit_thread = false;
- mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
+ mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
pa_ml = pa_mainloop_new();
ERR_FAIL_COND_V(pa_ml == NULL, ERR_CANT_OPEN);
@@ -287,75 +313,71 @@ float AudioDriverPulseAudio::get_latency() {
void AudioDriverPulseAudio::thread_func(void *p_udata) {
AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)p_udata;
+ unsigned int write_ofs = 0;
+ size_t avail_bytes = 0;
while (!ad->exit_thread) {
- if (!ad->active) {
- for (unsigned int i = 0; i < ad->pa_buffer_size; i++) {
- ad->samples_out[i] = 0;
- }
- } else {
- ad->lock();
+ size_t read_bytes = 0;
+ size_t written_bytes = 0;
- ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
-
- ad->unlock();
+ if (avail_bytes == 0) {
+ ad->lock();
+ ad->start_counting_ticks();
- if (ad->channels == ad->pa_map.channels) {
+ if (!ad->active) {
for (unsigned int i = 0; i < ad->pa_buffer_size; i++) {
- ad->samples_out[i] = ad->samples_in[i] >> 16;
+ ad->samples_out.write[i] = 0;
}
} else {
- // Uneven amount of channels
- unsigned int in_idx = 0;
- unsigned int out_idx = 0;
+ ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
- for (unsigned int i = 0; i < ad->buffer_frames; i++) {
- for (unsigned int j = 0; j < ad->pa_map.channels - 1; j++) {
- ad->samples_out[out_idx++] = ad->samples_in[in_idx++] >> 16;
+ if (ad->channels == ad->pa_map.channels) {
+ for (unsigned int i = 0; i < ad->pa_buffer_size; i++) {
+ ad->samples_out.write[i] = ad->samples_in[i] >> 16;
+ }
+ } else {
+ // Uneven amount of channels
+ unsigned int in_idx = 0;
+ 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++) {
+ 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++];
- uint32_t r = ad->samples_in[in_idx++];
- ad->samples_out[out_idx++] = (l >> 1 + r >> 1) >> 16;
}
}
- }
- int error_code;
- int byte_size = ad->pa_buffer_size * sizeof(int16_t);
+ avail_bytes = ad->pa_buffer_size * sizeof(int16_t);
+ write_ofs = 0;
+ ad->stop_counting_ticks();
+ ad->unlock();
+ }
ad->lock();
+ ad->start_counting_ticks();
int ret;
do {
ret = pa_mainloop_iterate(ad->pa_ml, 0, NULL);
} while (ret > 0);
- if (pa_stream_get_state(ad->pa_str) == PA_STREAM_READY) {
- const void *ptr = ad->samples_out.ptr();
- while (byte_size > 0) {
- size_t bytes = pa_stream_writable_size(ad->pa_str);
- if (bytes > 0) {
- if (bytes > byte_size) {
- bytes = byte_size;
- }
-
- ret = pa_stream_write(ad->pa_str, ptr, bytes, NULL, 0LL, PA_SEEK_RELATIVE);
- if (ret >= 0) {
- byte_size -= bytes;
- ptr = (const char *)ptr + bytes;
- }
+ if (avail_bytes > 0 && pa_stream_get_state(ad->pa_str) == PA_STREAM_READY) {
+ size_t bytes = pa_stream_writable_size(ad->pa_str);
+ if (bytes > 0) {
+ size_t bytes_to_write = MIN(bytes, avail_bytes);
+ 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");
} else {
- ret = pa_mainloop_iterate(ad->pa_ml, 0, NULL);
- if (ret == 0) {
- // If pa_mainloop_iterate returns 0 sleep for 1 msec to wait
- // for the stream to be able to process more bytes
- ad->unlock();
-
- OS::get_singleton()->delay_usec(1000);
-
- ad->lock();
- }
+ avail_bytes -= bytes_to_write;
+ write_ofs += bytes_to_write;
+ written_bytes += bytes_to_write;
}
}
}
@@ -380,7 +402,64 @@ void AudioDriverPulseAudio::thread_func(void *p_udata) {
}
}
+ if (ad->pa_rec_str && pa_stream_get_state(ad->pa_rec_str) == PA_STREAM_READY) {
+ size_t bytes = pa_stream_readable_size(ad->pa_rec_str);
+ if (bytes > 0) {
+ const void *ptr = NULL;
+ size_t maxbytes = ad->input_buffer.size() * sizeof(int16_t);
+
+ bytes = MIN(bytes, maxbytes);
+ ret = pa_stream_peek(ad->pa_rec_str, &ptr, &bytes);
+ if (ret != 0) {
+ ERR_PRINT("pa_stream_peek error");
+ } else {
+ int16_t *srcptr = (int16_t *)ptr;
+ for (size_t i = bytes >> 1; i > 0; i--) {
+ int32_t sample = int32_t(*srcptr++) << 16;
+ ad->input_buffer_write(sample);
+
+ if (ad->pa_rec_map.channels == 1) {
+ // In case input device is single channel convert it to Stereo
+ ad->input_buffer_write(sample);
+ }
+ }
+
+ read_bytes += bytes;
+ ret = pa_stream_drop(ad->pa_rec_str);
+ if (ret != 0) {
+ ERR_PRINT("pa_stream_drop error");
+ }
+ }
+ }
+
+ // User selected a new device, finish the current one so we'll init the new device
+ if (ad->capture_device_name != ad->capture_new_device) {
+ ad->capture_device_name = ad->capture_new_device;
+ ad->capture_finish_device();
+
+ Error err = ad->capture_init_device();
+ if (err != OK) {
+ ERR_PRINT("PulseAudio: capture_init_device error");
+ ad->capture_device_name = "Default";
+ ad->capture_new_device = "Default";
+
+ err = ad->capture_init_device();
+ if (err != OK) {
+ ad->active = false;
+ ad->exit_thread = true;
+ break;
+ }
+ }
+ }
+ }
+
+ ad->stop_counting_ticks();
ad->unlock();
+
+ // Let the thread rest a while if we haven't read or write anything
+ if (written_bytes == 0 && read_bytes == 0) {
+ OS::get_singleton()->delay_usec(1000);
+ }
}
ad->thread_exited = true;
@@ -403,7 +482,6 @@ AudioDriver::SpeakerMode AudioDriverPulseAudio::get_speaker_mode() const {
void AudioDriverPulseAudio::pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata) {
AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
- int ctr = 0;
// If eol is set to a positive number, you're at the end of the list
if (eol > 0) {
@@ -453,7 +531,9 @@ String AudioDriverPulseAudio::get_device() {
void AudioDriverPulseAudio::set_device(String device) {
+ lock();
new_device = device;
+ unlock();
}
void AudioDriverPulseAudio::lock() {
@@ -509,11 +589,163 @@ void AudioDriverPulseAudio::finish() {
thread = NULL;
}
+Error AudioDriverPulseAudio::capture_init_device() {
+
+ // If there is a specified device check that it is really present
+ if (capture_device_name != "Default") {
+ Array list = capture_get_device_list();
+ if (list.find(capture_device_name) == -1) {
+ capture_device_name = "Default";
+ capture_new_device = "Default";
+ }
+ }
+
+ detect_channels(true);
+ switch (pa_rec_map.channels) {
+ case 1: // Mono
+ case 2: // Stereo
+ break;
+
+ default:
+ WARN_PRINTS("PulseAudio: Unsupported number of input channels: " + itos(pa_rec_map.channels));
+ pa_channel_map_init_stereo(&pa_rec_map);
+ break;
+ }
+
+ print_verbose("PulseAudio: detected " + itos(pa_rec_map.channels) + " input channels");
+
+ pa_sample_spec spec;
+
+ spec.format = PA_SAMPLE_S16LE;
+ spec.channels = pa_rec_map.channels;
+ spec.rate = mix_rate;
+
+ int latency = 30;
+ input_buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
+ int buffer_size = input_buffer_frames * spec.channels;
+
+ pa_buffer_attr attr;
+ attr.fragsize = buffer_size * sizeof(int16_t);
+
+ pa_rec_str = pa_stream_new(pa_ctx, "Record", &spec, &pa_rec_map);
+ if (pa_rec_str == NULL) {
+ ERR_PRINTS("PulseAudio: pa_stream_new error: " + String(pa_strerror(pa_context_errno(pa_ctx))));
+ ERR_FAIL_V(ERR_CANT_OPEN);
+ }
+
+ const char *dev = capture_device_name == "Default" ? NULL : capture_device_name.utf8().get_data();
+ pa_stream_flags flags = pa_stream_flags(PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE);
+ int error_code = pa_stream_connect_record(pa_rec_str, dev, &attr, flags);
+ if (error_code < 0) {
+ ERR_PRINTS("PulseAudio: pa_stream_connect_record error: " + String(pa_strerror(error_code)));
+ ERR_FAIL_V(ERR_CANT_OPEN);
+ }
+
+ input_buffer.resize(input_buffer_frames * 8);
+ input_position = 0;
+ input_size = 0;
+
+ return OK;
+}
+
+void AudioDriverPulseAudio::capture_finish_device() {
+
+ if (pa_rec_str) {
+ int ret = pa_stream_disconnect(pa_rec_str);
+ if (ret != 0) {
+ ERR_PRINTS("PulseAudio: pa_stream_disconnect error: " + String(pa_strerror(ret)));
+ }
+ pa_stream_unref(pa_rec_str);
+ pa_rec_str = NULL;
+ }
+}
+
+Error AudioDriverPulseAudio::capture_start() {
+
+ lock();
+ Error err = capture_init_device();
+ unlock();
+
+ return err;
+}
+
+Error AudioDriverPulseAudio::capture_stop() {
+ lock();
+ capture_finish_device();
+ unlock();
+
+ return OK;
+}
+
+void AudioDriverPulseAudio::capture_set_device(const String &p_name) {
+
+ lock();
+ capture_new_device = p_name;
+ unlock();
+}
+
+void AudioDriverPulseAudio::pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata) {
+ AudioDriverPulseAudio *ad = (AudioDriverPulseAudio *)userdata;
+
+ // If eol is set to a positive number, you're at the end of the list
+ if (eol > 0) {
+ return;
+ }
+
+ if (l->monitor_of_sink == PA_INVALID_INDEX) {
+ ad->pa_rec_devices.push_back(l->name);
+ }
+
+ ad->pa_status++;
+}
+
+Array AudioDriverPulseAudio::capture_get_device_list() {
+
+ pa_rec_devices.clear();
+ pa_rec_devices.push_back("Default");
+
+ if (pa_ctx == NULL) {
+ return pa_rec_devices;
+ }
+
+ lock();
+
+ // Get the device list
+ pa_status = 0;
+ pa_operation *pa_op = pa_context_get_source_info_list(pa_ctx, pa_sourcelist_cb, (void *)this);
+ if (pa_op) {
+ while (pa_status == 0) {
+ int ret = pa_mainloop_iterate(pa_ml, 1, NULL);
+ if (ret < 0) {
+ ERR_PRINT("pa_mainloop_iterate error");
+ }
+ }
+
+ pa_operation_unref(pa_op);
+ } else {
+ ERR_PRINT("pa_context_get_server_info error");
+ }
+
+ unlock();
+
+ return pa_rec_devices;
+}
+
+String AudioDriverPulseAudio::capture_get_device() {
+
+ lock();
+ String name = capture_device_name;
+ unlock();
+
+ return name;
+}
+
AudioDriverPulseAudio::AudioDriverPulseAudio() {
pa_ml = NULL;
pa_ctx = NULL;
pa_str = NULL;
+ pa_rec_str = NULL;
mutex = NULL;
thread = NULL;
@@ -527,6 +759,7 @@ 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 b471f5f9d5..f8358a452b 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.h
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.h
@@ -47,22 +47,30 @@ class AudioDriverPulseAudio : public AudioDriver {
pa_mainloop *pa_ml;
pa_context *pa_ctx;
pa_stream *pa_str;
+ pa_stream *pa_rec_str;
pa_channel_map pa_map;
+ pa_channel_map pa_rec_map;
String device_name;
String new_device;
String default_device;
+ String capture_device_name;
+ String capture_new_device;
+ String capture_default_device;
+
Vector<int32_t> samples_in;
Vector<int16_t> samples_out;
unsigned int mix_rate;
unsigned int buffer_frames;
+ unsigned int input_buffer_frames;
unsigned int pa_buffer_size;
int channels;
int pa_ready;
int pa_status;
Array pa_devices;
+ Array pa_rec_devices;
bool active;
bool thread_exited;
@@ -72,13 +80,18 @@ class AudioDriverPulseAudio : public AudioDriver {
static void pa_state_cb(pa_context *c, void *userdata);
static void pa_sink_info_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata);
+ static void pa_source_info_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata);
static void pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata);
static void pa_sinklist_cb(pa_context *c, const pa_sink_info *l, int eol, void *userdata);
+ static void pa_sourcelist_cb(pa_context *c, const pa_source_info *l, int eol, void *userdata);
Error init_device();
void finish_device();
- void detect_channels();
+ Error capture_init_device();
+ void capture_finish_device();
+
+ void detect_channels(bool capture = false);
static void thread_func(void *p_udata);
@@ -91,15 +104,24 @@ public:
virtual void start();
virtual int get_mix_rate() const;
virtual SpeakerMode get_speaker_mode() const;
+
virtual Array get_device_list();
virtual String get_device();
virtual void set_device(String device);
+
+ virtual Array capture_get_device_list();
+ virtual void capture_set_device(const String &p_name);
+ virtual String capture_get_device();
+
virtual void lock();
virtual void unlock();
virtual void finish();
virtual float get_latency();
+ virtual Error capture_start();
+ virtual Error capture_stop();
+
AudioDriverPulseAudio();
~AudioDriverPulseAudio();
};
diff --git a/drivers/rtaudio/audio_driver_rtaudio.cpp b/drivers/rtaudio/audio_driver_rtaudio.cpp
index 457486797f..69830b542b 100644
--- a/drivers/rtaudio/audio_driver_rtaudio.cpp
+++ b/drivers/rtaudio/audio_driver_rtaudio.cpp
@@ -88,7 +88,7 @@ Error AudioDriverRtAudio::init() {
// FIXME: Adapt to the OutputFormat -> SpeakerMode change
/*
- String channels = GLOBAL_DEF("audio/output","stereo");
+ String channels = GLOBAL_DEF_RST("audio/output","stereo");
if (channels=="5.1")
output_format=OUTPUT_5_1;
@@ -108,14 +108,11 @@ Error AudioDriverRtAudio::init() {
options.numberOfBuffers = 4;
parameters.firstChannel = 0;
- mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
+ mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
int latency = GLOBAL_DEF("audio/output_latency", DEFAULT_OUTPUT_LATENCY);
unsigned int buffer_frames = closest_power_of_2(latency * mix_rate / 1000);
-
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
- }
+ print_verbose("Audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
short int tries = 2;
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index c25d34125d..ca16c6fcae 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -106,7 +106,6 @@ Error FileAccessUnix::_open(const String &p_path, int p_mode_flags) {
if (is_backup_save_enabled() && (p_mode_flags & WRITE) && !(p_mode_flags & READ)) {
save_path = path;
path = path + ".tmp";
- //print_line("saving instead to "+path);
}
f = fopen(path.utf8().get_data(), mode_string);
@@ -134,9 +133,6 @@ void FileAccessUnix::close() {
}
if (save_path != "") {
-
- //unlink(save_path.utf8().get_data());
- //print_line("renaming...");
int rename_error = rename((save_path + ".tmp").utf8().get_data(), save_path.utf8().get_data());
if (rename_error && close_fail_notify) {
@@ -291,8 +287,7 @@ uint64_t FileAccessUnix::_get_modified_time(const String &p_file) {
if (!err) {
return flags.st_mtime;
} else {
- print_line("ERROR IN: " + p_file);
-
+ ERR_EXPLAIN("Failed to get modified time for: " + p_file);
ERR_FAIL_V(0);
};
}
diff --git a/drivers/wasapi/audio_driver_wasapi.cpp b/drivers/wasapi/audio_driver_wasapi.cpp
index e1680601ad..11abe3256e 100644
--- a/drivers/wasapi/audio_driver_wasapi.cpp
+++ b/drivers/wasapi/audio_driver_wasapi.cpp
@@ -52,8 +52,22 @@ const CLSID CLSID_MMDeviceEnumerator = __uuidof(MMDeviceEnumerator);
const IID IID_IMMDeviceEnumerator = __uuidof(IMMDeviceEnumerator);
const IID IID_IAudioClient = __uuidof(IAudioClient);
const IID IID_IAudioRenderClient = __uuidof(IAudioRenderClient);
+const IID IID_IAudioCaptureClient = __uuidof(IAudioCaptureClient);
-static bool default_device_changed = false;
+#define SAFE_RELEASE(memory) \
+ if ((memory) != NULL) { \
+ (memory)->Release(); \
+ (memory) = NULL; \
+ }
+
+#define REFTIMES_PER_SEC 10000000
+#define REFTIMES_PER_MILLISEC 10000
+
+#define CAPTURE_BUFFER_CHANNELS 2
+
+static StringName capture_device_id;
+static bool default_render_device_changed = false;
+static bool default_capture_device_changed = false;
class CMMNotificationClient : public IMMNotificationClient {
LONG _cRef;
@@ -109,8 +123,13 @@ public:
}
HRESULT STDMETHODCALLTYPE OnDefaultDeviceChanged(EDataFlow flow, ERole role, LPCWSTR pwstrDeviceId) {
- if (flow == eRender && role == eConsole) {
- default_device_changed = true;
+ if (role == eConsole) {
+ if (flow == eRender) {
+ default_render_device_changed = true;
+ } else if (flow == eCapture) {
+ default_capture_device_changed = true;
+ capture_device_id = String(pwstrDeviceId);
+ }
}
return S_OK;
@@ -123,7 +142,7 @@ public:
static CMMNotificationClient notif_client;
-Error AudioDriverWASAPI::init_device(bool reinit) {
+Error AudioDriverWASAPI::audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit) {
WAVEFORMATEX *pwfex;
IMMDeviceEnumerator *enumerator = NULL;
@@ -134,12 +153,12 @@ Error AudioDriverWASAPI::init_device(bool reinit) {
HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
- if (device_name == "Default") {
- hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
+ if (p_device->device_name == "Default") {
+ hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device);
} else {
IMMDeviceCollection *devices = NULL;
- hr = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices);
+ hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
LPWSTR strId = NULL;
@@ -165,7 +184,7 @@ Error AudioDriverWASAPI::init_device(bool reinit) {
hr = props->GetValue(PKEY_Device_FriendlyName, &propvar);
ERR_BREAK(hr != S_OK);
- if (device_name == String(propvar.pwszVal)) {
+ if (p_device->device_name == String(propvar.pwszVal)) {
hr = device->GetId(&strId);
ERR_BREAK(hr != S_OK);
@@ -186,9 +205,10 @@ Error AudioDriverWASAPI::init_device(bool reinit) {
}
if (device == NULL) {
- hr = enumerator->GetDefaultAudioEndpoint(eRender, eConsole, &device);
+ hr = enumerator->GetDefaultAudioEndpoint(p_capture ? eCapture : eRender, eConsole, &device);
}
}
+
if (reinit) {
// In case we're trying to re-initialize the device prevent throwing this error on the console,
// otherwise if there is currently no device available this will spam the console.
@@ -200,11 +220,15 @@ Error AudioDriverWASAPI::init_device(bool reinit) {
}
hr = enumerator->RegisterEndpointNotificationCallback(&notif_client);
+ SAFE_RELEASE(enumerator)
+
if (hr != S_OK) {
ERR_PRINT("WASAPI: RegisterEndpointNotificationCallback error");
}
- hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&audio_client);
+ hr = device->Activate(IID_IAudioClient, CLSCTX_ALL, NULL, (void **)&p_device->audio_client);
+ SAFE_RELEASE(device)
+
if (reinit) {
if (hr != S_OK) {
return ERR_CANT_OPEN;
@@ -213,119 +237,151 @@ Error AudioDriverWASAPI::init_device(bool reinit) {
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
}
- hr = audio_client->GetMixFormat(&pwfex);
+ hr = p_device->audio_client->GetMixFormat(&pwfex);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
// Since we're using WASAPI Shared Mode we can't control any of these, we just tag along
- wasapi_channels = pwfex->nChannels;
- format_tag = pwfex->wFormatTag;
- bits_per_sample = pwfex->wBitsPerSample;
-
- switch (wasapi_channels) {
- case 2: // Stereo
- case 4: // Surround 3.1
- case 6: // Surround 5.1
- case 8: // Surround 7.1
- channels = wasapi_channels;
- break;
+ p_device->channels = pwfex->nChannels;
+ p_device->format_tag = pwfex->wFormatTag;
+ p_device->bits_per_sample = pwfex->wBitsPerSample;
+ p_device->frame_size = (p_device->bits_per_sample / 8) * p_device->channels;
- default:
- WARN_PRINTS("WASAPI: Unsupported number of channels: " + itos(wasapi_channels));
- channels = 2;
- break;
- }
-
- if (format_tag == WAVE_FORMAT_EXTENSIBLE) {
+ if (p_device->format_tag == WAVE_FORMAT_EXTENSIBLE) {
WAVEFORMATEXTENSIBLE *wfex = (WAVEFORMATEXTENSIBLE *)pwfex;
if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_PCM) {
- format_tag = WAVE_FORMAT_PCM;
+ p_device->format_tag = WAVE_FORMAT_PCM;
} else if (wfex->SubFormat == KSDATAFORMAT_SUBTYPE_IEEE_FLOAT) {
- format_tag = WAVE_FORMAT_IEEE_FLOAT;
+ p_device->format_tag = WAVE_FORMAT_IEEE_FLOAT;
} else {
ERR_PRINT("WASAPI: Format not supported");
ERR_FAIL_V(ERR_CANT_OPEN);
}
} else {
- if (format_tag != WAVE_FORMAT_PCM && format_tag != WAVE_FORMAT_IEEE_FLOAT) {
+ if (p_device->format_tag != WAVE_FORMAT_PCM && p_device->format_tag != WAVE_FORMAT_IEEE_FLOAT) {
ERR_PRINT("WASAPI: Format not supported");
ERR_FAIL_V(ERR_CANT_OPEN);
}
}
- DWORD streamflags = AUDCLNT_STREAMFLAGS_EVENTCALLBACK;
+ DWORD streamflags = 0;
if (mix_rate != pwfex->nSamplesPerSec) {
streamflags |= AUDCLNT_STREAMFLAGS_RATEADJUST;
pwfex->nSamplesPerSec = mix_rate;
pwfex->nAvgBytesPerSec = pwfex->nSamplesPerSec * pwfex->nChannels * (pwfex->wBitsPerSample / 8);
}
- hr = audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, 0, 0, pwfex, NULL);
+ hr = p_device->audio_client->Initialize(AUDCLNT_SHAREMODE_SHARED, streamflags, p_capture ? REFTIMES_PER_SEC : 0, 0, pwfex, NULL);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
- event = CreateEvent(NULL, FALSE, FALSE, NULL);
- ERR_FAIL_COND_V(event == NULL, ERR_CANT_OPEN);
-
- hr = audio_client->SetEventHandle(event);
+ if (p_capture) {
+ hr = p_device->audio_client->GetService(IID_IAudioCaptureClient, (void **)&p_device->capture_client);
+ } else {
+ hr = p_device->audio_client->GetService(IID_IAudioRenderClient, (void **)&p_device->render_client);
+ }
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
- hr = audio_client->GetService(IID_IAudioRenderClient, (void **)&render_client);
- ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
+ // Free memory
+ CoTaskMemFree(pwfex);
+ SAFE_RELEASE(device)
+
+ return OK;
+}
+
+Error AudioDriverWASAPI::init_render_device(bool reinit) {
+
+ Error err = audio_device_init(&audio_output, false, reinit);
+ if (err != OK)
+ return err;
+
+ switch (audio_output.channels) {
+ case 2: // Stereo
+ case 4: // Surround 3.1
+ case 6: // Surround 5.1
+ case 8: // Surround 7.1
+ channels = audio_output.channels;
+ break;
+
+ default:
+ WARN_PRINTS("WASAPI: Unsupported number of channels: " + itos(audio_output.channels));
+ channels = 2;
+ break;
+ }
UINT32 max_frames;
- hr = audio_client->GetBufferSize(&max_frames);
+ HRESULT hr = audio_output.audio_client->GetBufferSize(&max_frames);
ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
// Due to WASAPI Shared Mode we have no control of the buffer size
buffer_frames = max_frames;
// Sample rate is independent of channels (ref: https://stackoverflow.com/questions/11048825/audio-sample-frequency-rely-on-channels)
- buffer_size = buffer_frames * channels;
- samples_in.resize(buffer_size);
+ samples_in.resize(buffer_frames * channels);
- if (OS::get_singleton()->is_stdout_verbose()) {
- print_line("WASAPI: detected " + itos(channels) + " channels");
- print_line("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
- }
+ input_position = 0;
+ input_size = 0;
+
+ print_verbose("WASAPI: detected " + itos(channels) + " channels");
+ print_verbose("WASAPI: audio buffer frames: " + itos(buffer_frames) + " calculated latency: " + itos(buffer_frames * 1000 / mix_rate) + "ms");
return OK;
}
-Error AudioDriverWASAPI::finish_device() {
+Error AudioDriverWASAPI::init_capture_device(bool reinit) {
- if (audio_client) {
- if (active) {
- audio_client->Stop();
- active = false;
- }
+ Error err = audio_device_init(&audio_input, true, reinit);
+ if (err != OK)
+ return err;
- audio_client->Release();
- audio_client = NULL;
- }
+ // Get the max frames
+ UINT32 max_frames;
+ HRESULT hr = audio_input.audio_client->GetBufferSize(&max_frames);
+ ERR_FAIL_COND_V(hr != S_OK, ERR_CANT_OPEN);
- if (render_client) {
- render_client->Release();
- render_client = NULL;
- }
+ // Set the buffer size
+ input_buffer.resize(max_frames * CAPTURE_BUFFER_CHANNELS);
+ input_position = 0;
+ input_size = 0;
+
+ return OK;
+}
+
+Error AudioDriverWASAPI::audio_device_finish(AudioDeviceWASAPI *p_device) {
- if (audio_client) {
- audio_client->Release();
- audio_client = NULL;
+ if (p_device->active) {
+ if (p_device->audio_client) {
+ p_device->audio_client->Stop();
+ }
+
+ p_device->active = false;
}
+ SAFE_RELEASE(p_device->audio_client)
+ SAFE_RELEASE(p_device->render_client)
+ SAFE_RELEASE(p_device->capture_client)
+
return OK;
}
+Error AudioDriverWASAPI::finish_render_device() {
+
+ return audio_device_finish(&audio_output);
+}
+
+Error AudioDriverWASAPI::finish_capture_device() {
+
+ return audio_device_finish(&audio_input);
+}
+
Error AudioDriverWASAPI::init() {
- mix_rate = GLOBAL_DEF("audio/mix_rate", DEFAULT_MIX_RATE);
+ mix_rate = GLOBAL_DEF_RST("audio/mix_rate", DEFAULT_MIX_RATE);
- Error err = init_device();
+ Error err = init_render_device();
if (err != OK) {
- ERR_PRINT("WASAPI: init_device error");
+ ERR_PRINT("WASAPI: init_render_device error");
}
- active = false;
exit_thread = false;
thread_exited = false;
@@ -335,22 +391,6 @@ Error AudioDriverWASAPI::init() {
return OK;
}
-Error AudioDriverWASAPI::reopen() {
- Error err = finish_device();
- if (err != OK) {
- ERR_PRINT("WASAPI: finish_device error");
- } else {
- err = init_device();
- if (err != OK) {
- ERR_PRINT("WASAPI: init_device error");
- } else {
- start();
- }
- }
-
- return err;
-}
-
int AudioDriverWASAPI::get_mix_rate() const {
return mix_rate;
@@ -361,7 +401,7 @@ AudioDriver::SpeakerMode AudioDriverWASAPI::get_speaker_mode() const {
return get_speaker_mode_by_total_channels(channels);
}
-Array AudioDriverWASAPI::get_device_list() {
+Array AudioDriverWASAPI::audio_device_get_list(bool p_capture) {
Array list;
IMMDeviceCollection *devices = NULL;
@@ -374,7 +414,7 @@ Array AudioDriverWASAPI::get_device_list() {
HRESULT hr = CoCreateInstance(CLSID_MMDeviceEnumerator, NULL, CLSCTX_ALL, IID_IMMDeviceEnumerator, (void **)&enumerator);
ERR_FAIL_COND_V(hr != S_OK, Array());
- hr = enumerator->EnumAudioEndpoints(eRender, DEVICE_STATE_ACTIVE, &devices);
+ hr = enumerator->EnumAudioEndpoints(p_capture ? eCapture : eRender, DEVICE_STATE_ACTIVE, &devices);
ERR_FAIL_COND_V(hr != S_OK, Array());
UINT count = 0;
@@ -409,19 +449,63 @@ Array AudioDriverWASAPI::get_device_list() {
return list;
}
+Array AudioDriverWASAPI::get_device_list() {
+
+ return audio_device_get_list(false);
+}
+
String AudioDriverWASAPI::get_device() {
- return device_name;
+ lock();
+ String name = audio_output.device_name;
+ unlock();
+
+ return name;
}
void AudioDriverWASAPI::set_device(String device) {
- new_device = device;
+ lock();
+ audio_output.new_device = device;
+ unlock();
}
-void AudioDriverWASAPI::write_sample(AudioDriverWASAPI *ad, BYTE *buffer, int i, int32_t sample) {
- if (ad->format_tag == WAVE_FORMAT_PCM) {
- switch (ad->bits_per_sample) {
+int32_t AudioDriverWASAPI::read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i) {
+ if (format_tag == WAVE_FORMAT_PCM) {
+ int32_t sample = 0;
+ switch (bits_per_sample) {
+ case 8:
+ sample = int32_t(((int8_t *)buffer)[i]) << 24;
+ break;
+
+ case 16:
+ sample = int32_t(((int16_t *)buffer)[i]) << 16;
+ break;
+
+ case 24:
+ sample |= int32_t(((int8_t *)buffer)[i * 3 + 2]) << 24;
+ sample |= int32_t(((int8_t *)buffer)[i * 3 + 1]) << 16;
+ sample |= int32_t(((int8_t *)buffer)[i * 3 + 0]) << 8;
+ break;
+
+ case 32:
+ sample = ((int32_t *)buffer)[i];
+ break;
+ }
+
+ return sample;
+ } else if (format_tag == WAVE_FORMAT_IEEE_FLOAT) {
+ return int32_t(((float *)buffer)[i] * 32768.0) << 16;
+ } else {
+ ERR_PRINT("WASAPI: Unknown format tag");
+ }
+
+ return 0;
+}
+
+void AudioDriverWASAPI::write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample) {
+ if (format_tag == WAVE_FORMAT_PCM) {
+ switch (bits_per_sample) {
case 8:
((int8_t *)buffer)[i] = sample >> 24;
break;
@@ -440,125 +524,221 @@ void AudioDriverWASAPI::write_sample(AudioDriverWASAPI *ad, BYTE *buffer, int i,
((int32_t *)buffer)[i] = sample;
break;
}
- } else if (ad->format_tag == WAVE_FORMAT_IEEE_FLOAT) {
+ } else if (format_tag == WAVE_FORMAT_IEEE_FLOAT) {
((float *)buffer)[i] = (sample >> 16) / 32768.f;
} else {
ERR_PRINT("WASAPI: Unknown format tag");
- ad->exit_thread = true;
}
}
void AudioDriverWASAPI::thread_func(void *p_udata) {
AudioDriverWASAPI *ad = (AudioDriverWASAPI *)p_udata;
+ uint32_t avail_frames = 0;
+ uint32_t write_ofs = 0;
while (!ad->exit_thread) {
- if (ad->active) {
+
+ uint32_t read_frames = 0;
+ uint32_t written_frames = 0;
+
+ if (avail_frames == 0) {
ad->lock();
+ ad->start_counting_ticks();
+
+ if (ad->audio_output.active) {
+ ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
+ } else {
+ for (unsigned int i = 0; i < ad->samples_in.size(); i++) {
+ ad->samples_in.write[i] = 0;
+ }
+ }
- ad->audio_server_process(ad->buffer_frames, ad->samples_in.ptrw());
+ avail_frames = ad->buffer_frames;
+ write_ofs = 0;
+ ad->stop_counting_ticks();
ad->unlock();
- } else {
- for (unsigned int i = 0; i < ad->buffer_size; i++) {
- ad->samples_in[i] = 0;
- }
}
- unsigned int left_frames = ad->buffer_frames;
- unsigned int buffer_idx = 0;
- while (left_frames > 0 && ad->audio_client) {
- WaitForSingleObject(ad->event, 1000);
+ ad->lock();
+ ad->start_counting_ticks();
+
+ if (avail_frames > 0 && ad->audio_output.audio_client) {
UINT32 cur_frames;
- HRESULT hr = ad->audio_client->GetCurrentPadding(&cur_frames);
+ bool invalidated = false;
+ HRESULT hr = ad->audio_output.audio_client->GetCurrentPadding(&cur_frames);
if (hr == S_OK) {
- // Check how much frames are available on the WASAPI buffer
- UINT32 avail_frames = ad->buffer_frames - cur_frames;
- UINT32 write_frames = avail_frames > left_frames ? left_frames : avail_frames;
-
- BYTE *buffer = NULL;
- hr = ad->render_client->GetBuffer(write_frames, &buffer);
- if (hr == S_OK) {
- // We're using WASAPI Shared Mode so we must convert the buffer
- if (ad->channels == ad->wasapi_channels) {
- for (unsigned int i = 0; i < write_frames * ad->channels; i++) {
- ad->write_sample(ad, buffer, i, ad->samples_in[buffer_idx++]);
- }
- } else {
- for (unsigned int i = 0; i < write_frames; i++) {
- for (unsigned int j = 0; j < MIN(ad->channels, ad->wasapi_channels); j++) {
- ad->write_sample(ad, buffer, i * ad->wasapi_channels + j, ad->samples_in[buffer_idx++]);
+ // Check how much frames are available on the WASAPI buffer
+ UINT32 write_frames = MIN(ad->buffer_frames - cur_frames, avail_frames);
+ if (write_frames > 0) {
+ BYTE *buffer = NULL;
+ hr = ad->audio_output.render_client->GetBuffer(write_frames, &buffer);
+ if (hr == S_OK) {
+
+ // We're using WASAPI Shared Mode so we must convert the buffer
+ if (ad->channels == ad->audio_output.channels) {
+ for (unsigned int i = 0; i < write_frames * ad->channels; i++) {
+ ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i, ad->samples_in.write[write_ofs++]);
}
- if (ad->wasapi_channels > ad->channels) {
- for (unsigned int j = ad->channels; j < ad->wasapi_channels; j++) {
- ad->write_sample(ad, buffer, i * ad->wasapi_channels + j, 0);
+ } else {
+ for (unsigned int i = 0; i < write_frames; i++) {
+ for (unsigned int j = 0; j < MIN(ad->channels, ad->audio_output.channels); j++) {
+ ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + j, ad->samples_in.write[write_ofs++]);
+ }
+ if (ad->audio_output.channels > ad->channels) {
+ for (unsigned int j = ad->channels; j < ad->audio_output.channels; j++) {
+ ad->write_sample(ad->audio_output.format_tag, ad->audio_output.bits_per_sample, buffer, i * ad->audio_output.channels + j, 0);
+ }
}
}
}
- }
- hr = ad->render_client->ReleaseBuffer(write_frames, 0);
- if (hr != S_OK) {
- ERR_PRINT("WASAPI: Release buffer error");
- }
-
- left_frames -= write_frames;
- } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
- // Device is not valid anymore, reopen it
+ hr = ad->audio_output.render_client->ReleaseBuffer(write_frames, 0);
+ if (hr != S_OK) {
+ ERR_PRINT("WASAPI: Release buffer error");
+ }
- Error err = ad->finish_device();
- if (err != OK) {
- ERR_PRINT("WASAPI: finish_device error");
+ avail_frames -= write_frames;
+ written_frames += write_frames;
+ } else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
+ // Device is not valid anymore, reopen it
+
+ Error err = ad->finish_render_device();
+ if (err != OK) {
+ ERR_PRINT("WASAPI: finish_render_device error");
+ } else {
+ // We reopened the device and samples_in may have resized, so invalidate the current avail_frames
+ avail_frames = 0;
+ }
} else {
- // We reopened the device and samples_in may have resized, so invalidate the current left_frames
- left_frames = 0;
+ ERR_PRINT("WASAPI: Get buffer error");
+ ad->exit_thread = true;
}
- } else {
- ERR_PRINT("WASAPI: Get buffer error");
- ad->exit_thread = true;
}
} else if (hr == AUDCLNT_E_DEVICE_INVALIDATED) {
- // Device is not valid anymore, reopen it
+ invalidated = true;
+ } else {
+ ERR_PRINT("WASAPI: GetCurrentPadding error");
+ }
- Error err = ad->finish_device();
+ if (invalidated) {
+ // Device is not valid anymore
+ WARN_PRINT("WASAPI: Current device invalidated, closing device");
+
+ Error err = ad->finish_render_device();
if (err != OK) {
- ERR_PRINT("WASAPI: finish_device error");
- } else {
- // We reopened the device and samples_in may have resized, so invalidate the current left_frames
- left_frames = 0;
+ ERR_PRINT("WASAPI: finish_render_device error");
}
- } else {
- ERR_PRINT("WASAPI: GetCurrentPadding error");
}
}
// If we're using the Default device and it changed finish it so we'll re-init the device
- if (ad->device_name == "Default" && default_device_changed) {
- Error err = ad->finish_device();
+ if (ad->audio_output.device_name == "Default" && default_render_device_changed) {
+ Error err = ad->finish_render_device();
if (err != OK) {
- ERR_PRINT("WASAPI: finish_device error");
+ ERR_PRINT("WASAPI: finish_render_device error");
}
- default_device_changed = false;
+ default_render_device_changed = false;
}
// User selected a new device, finish the current one so we'll init the new device
- if (ad->device_name != ad->new_device) {
- ad->device_name = ad->new_device;
- Error err = ad->finish_device();
+ if (ad->audio_output.device_name != ad->audio_output.new_device) {
+ ad->audio_output.device_name = ad->audio_output.new_device;
+ Error err = ad->finish_render_device();
if (err != OK) {
- ERR_PRINT("WASAPI: finish_device error");
+ ERR_PRINT("WASAPI: finish_render_device error");
}
}
- if (!ad->audio_client) {
- Error err = ad->init_device(true);
+ if (!ad->audio_output.audio_client) {
+ Error err = ad->init_render_device(true);
if (err == OK) {
ad->start();
}
}
+
+ if (ad->audio_input.active) {
+ UINT32 packet_length = 0;
+ BYTE *data;
+ UINT32 num_frames_available;
+ DWORD flags;
+
+ HRESULT hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length);
+ if (hr == S_OK) {
+ while (packet_length != 0) {
+ hr = ad->audio_input.capture_client->GetBuffer(&data, &num_frames_available, &flags, NULL, NULL);
+ ERR_BREAK(hr != S_OK);
+
+ // fixme: Only works for floating point atm
+ for (int j = 0; j < num_frames_available; j++) {
+ int32_t l, r;
+
+ if (flags & AUDCLNT_BUFFERFLAGS_SILENT) {
+ l = r = 0;
+ } else {
+ if (ad->audio_input.channels == 2) {
+ l = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j * 2);
+ r = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j * 2 + 1);
+ } else if (ad->audio_input.channels == 1) {
+ l = r = read_sample(ad->audio_input.format_tag, ad->audio_input.bits_per_sample, data, j);
+ } else {
+ l = r = 0;
+ ERR_PRINT("WASAPI: unsupported channel count in microphone!");
+ }
+ }
+
+ ad->input_buffer_write(l);
+ ad->input_buffer_write(r);
+ }
+
+ read_frames += num_frames_available;
+
+ hr = ad->audio_input.capture_client->ReleaseBuffer(num_frames_available);
+ ERR_BREAK(hr != S_OK);
+
+ hr = ad->audio_input.capture_client->GetNextPacketSize(&packet_length);
+ ERR_BREAK(hr != S_OK);
+ }
+ }
+
+ // If we're using the Default device and it changed finish it so we'll re-init the device
+ if (ad->audio_input.device_name == "Default" && default_capture_device_changed) {
+ Error err = ad->finish_capture_device();
+ if (err != OK) {
+ ERR_PRINT("WASAPI: finish_capture_device error");
+ }
+
+ default_capture_device_changed = false;
+ }
+
+ // User selected a new device, finish the current one so we'll init the new device
+ if (ad->audio_input.device_name != ad->audio_input.new_device) {
+ ad->audio_input.device_name = ad->audio_input.new_device;
+ Error err = ad->finish_capture_device();
+ if (err != OK) {
+ ERR_PRINT("WASAPI: finish_capture_device error");
+ }
+ }
+
+ if (!ad->audio_input.audio_client) {
+ Error err = ad->init_capture_device(true);
+ if (err == OK) {
+ ad->capture_start();
+ }
+ }
+ }
+
+ ad->stop_counting_ticks();
+ ad->unlock();
+
+ // Let the thread rest a while if we haven't read or write anything
+ if (written_frames == 0 && read_frames == 0) {
+ OS::get_singleton()->delay_usec(1000);
+ }
}
ad->thread_exited = true;
@@ -566,12 +746,12 @@ void AudioDriverWASAPI::thread_func(void *p_udata) {
void AudioDriverWASAPI::start() {
- if (audio_client) {
- HRESULT hr = audio_client->Start();
+ if (audio_output.audio_client) {
+ HRESULT hr = audio_output.audio_client->Start();
if (hr != S_OK) {
ERR_PRINT("WASAPI: Start failed");
} else {
- active = true;
+ audio_output.active = true;
}
}
}
@@ -598,7 +778,8 @@ void AudioDriverWASAPI::finish() {
thread = NULL;
}
- finish_device();
+ finish_capture_device();
+ finish_render_device();
if (mutex) {
memdelete(mutex);
@@ -606,30 +787,70 @@ void AudioDriverWASAPI::finish() {
}
}
+Error AudioDriverWASAPI::capture_start() {
+
+ Error err = init_capture_device();
+ if (err != OK) {
+ ERR_PRINT("WASAPI: init_capture_device error");
+ return err;
+ }
+
+ if (audio_input.active == false) {
+ audio_input.audio_client->Start();
+ audio_input.active = true;
+
+ return OK;
+ }
+
+ return FAILED;
+}
+
+Error AudioDriverWASAPI::capture_stop() {
+
+ if (audio_input.active == true) {
+ audio_input.audio_client->Stop();
+ audio_input.active = false;
+
+ return OK;
+ }
+
+ return FAILED;
+}
+
+void AudioDriverWASAPI::capture_set_device(const String &p_name) {
+
+ lock();
+ audio_input.new_device = p_name;
+ unlock();
+}
+
+Array AudioDriverWASAPI::capture_get_device_list() {
+
+ return audio_device_get_list(true);
+}
+
+String AudioDriverWASAPI::capture_get_device() {
+
+ lock();
+ String name = audio_input.device_name;
+ unlock();
+
+ return name;
+}
+
AudioDriverWASAPI::AudioDriverWASAPI() {
- audio_client = NULL;
- render_client = NULL;
mutex = NULL;
thread = NULL;
- format_tag = 0;
- bits_per_sample = 0;
-
samples_in.clear();
- buffer_size = 0;
channels = 0;
- wasapi_channels = 0;
mix_rate = 0;
buffer_frames = 0;
thread_exited = false;
exit_thread = false;
- active = false;
-
- device_name = "Default";
- new_device = "Default";
}
#endif
diff --git a/drivers/wasapi/audio_driver_wasapi.h b/drivers/wasapi/audio_driver_wasapi.h
index c97f4c288c..3d94f3ba49 100644
--- a/drivers/wasapi/audio_driver_wasapi.h
+++ b/drivers/wasapi/audio_driver_wasapi.h
@@ -43,36 +43,63 @@
class AudioDriverWASAPI : public AudioDriver {
- HANDLE event;
- IAudioClient *audio_client;
- IAudioRenderClient *render_client;
+ class AudioDeviceWASAPI {
+ public:
+ IAudioClient *audio_client;
+ IAudioRenderClient *render_client;
+ IAudioCaptureClient *capture_client;
+ bool active;
+
+ WORD format_tag;
+ WORD bits_per_sample;
+ unsigned int channels;
+ unsigned int frame_size;
+
+ String device_name;
+ String new_device;
+
+ AudioDeviceWASAPI() {
+ audio_client = NULL;
+ render_client = NULL;
+ capture_client = NULL;
+ active = false;
+ format_tag = 0;
+ bits_per_sample = 0;
+ channels = 0;
+ frame_size = 0;
+ device_name = "Default";
+ new_device = "Default";
+ }
+ };
+
+ AudioDeviceWASAPI audio_input;
+ AudioDeviceWASAPI audio_output;
+
Mutex *mutex;
Thread *thread;
- String device_name;
- String new_device;
-
- WORD format_tag;
- WORD bits_per_sample;
-
Vector<int32_t> samples_in;
- unsigned int buffer_size;
unsigned int channels;
- unsigned int wasapi_channels;
int mix_rate;
int buffer_frames;
bool thread_exited;
mutable bool exit_thread;
- bool active;
- _FORCE_INLINE_ void write_sample(AudioDriverWASAPI *ad, BYTE *buffer, int i, int32_t sample);
+ static _FORCE_INLINE_ void write_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i, int32_t sample);
+ static _FORCE_INLINE_ int32_t read_sample(WORD format_tag, int bits_per_sample, BYTE *buffer, int i);
static void thread_func(void *p_udata);
- Error init_device(bool reinit = false);
- Error finish_device();
- Error reopen();
+ Error init_render_device(bool reinit = false);
+ Error init_capture_device(bool reinit = false);
+
+ Error finish_render_device();
+ Error finish_capture_device();
+
+ Error audio_device_init(AudioDeviceWASAPI *p_device, bool p_capture, bool reinit);
+ Error audio_device_finish(AudioDeviceWASAPI *p_device);
+ Array audio_device_get_list(bool p_capture);
public:
virtual const char *get_name() const {
@@ -90,6 +117,12 @@ public:
virtual void unlock();
virtual void finish();
+ virtual Error capture_start();
+ virtual Error capture_stop();
+ virtual Array capture_get_device_list();
+ virtual void capture_set_device(const String &p_name);
+ virtual String capture_get_device();
+
AudioDriverWASAPI();
};
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index aa0fd34e0a..b4492a2022 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -31,11 +31,13 @@
#ifdef WINDOWS_ENABLED
#include "file_access_windows.h"
-#include "os/os.h"
-#include "shlwapi.h"
+
+#include "core/os/os.h"
+#include "core/print_string.h"
+
+#include <shlwapi.h>
#include <windows.h>
-#include "print_string.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <tchar.h>
@@ -133,17 +135,12 @@ void FileAccessWindows::close() {
if (save_path != "") {
- //unlink(save_path.utf8().get_data());
- //print_line("renaming...");
- //_wunlink(save_path.c_str()); //unlink if exists
- //int rename_error = _wrename((save_path+".tmp").c_str(),save_path.c_str());
-
bool rename_error = true;
int attempts = 4;
while (rename_error && attempts) {
- // This workaround of trying multiple times is added to deal with paranoid Windows
- // antiviruses that love reading just written files even if they are not executable, thus
- // locking the file and preventing renaming from happening.
+ // This workaround of trying multiple times is added to deal with paranoid Windows
+ // antiviruses that love reading just written files even if they are not executable, thus
+ // locking the file and preventing renaming from happening.
#ifdef UWP_ENABLED
// UWP has no PathFileExists, so we check attributes instead
@@ -305,11 +302,10 @@ uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
return st.st_mtime;
} else {
- print_line("no access to " + file);
+ ERR_EXPLAIN("Failed to get modified time for: " + file);
+ ERR_FAIL_V(0);
}
-
- ERR_FAIL_V(0);
-};
+}
FileAccessWindows::FileAccessWindows() {
diff --git a/drivers/winmidi/SCsub b/drivers/winmidi/SCsub
new file mode 100644
index 0000000000..233593b0f9
--- /dev/null
+++ b/drivers/winmidi/SCsub
@@ -0,0 +1,8 @@
+#!/usr/bin/env python
+
+Import('env')
+
+# Driver source files
+env.add_source_files(env.drivers_sources, "*.cpp")
+
+Export('env')
diff --git a/drivers/winmidi/win_midi.cpp b/drivers/winmidi/win_midi.cpp
new file mode 100644
index 0000000000..63f7f13685
--- /dev/null
+++ b/drivers/winmidi/win_midi.cpp
@@ -0,0 +1,106 @@
+/*************************************************************************/
+/* win_midi.cpp */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef WINMIDI_ENABLED
+
+#include "win_midi.h"
+#include "print_string.h"
+
+void MIDIDriverWinMidi::read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2) {
+
+ if (wMsg == MIM_DATA) {
+ receive_input_packet((uint64_t)dwParam2, (uint8_t *)&dwParam1, 3);
+ }
+}
+
+Error MIDIDriverWinMidi::open() {
+
+ for (UINT i = 0; i < midiInGetNumDevs(); i++) {
+ HMIDIIN midi_in;
+
+ MMRESULT res = midiInOpen(&midi_in, i, (DWORD_PTR)read, (DWORD_PTR)this, CALLBACK_FUNCTION);
+ if (res == MMSYSERR_NOERROR) {
+ midiInStart(midi_in);
+ connected_sources.insert(i, midi_in);
+ } else {
+ char err[256];
+ midiInGetErrorText(res, err, 256);
+ ERR_PRINTS("midiInOpen error: " + String(err));
+
+ MIDIINCAPS caps;
+ res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS));
+ if (res == MMSYSERR_NOERROR) {
+ ERR_PRINTS("Can't open MIDI device \"" + String(caps.szPname) + "\", is it being used by another application?");
+ }
+ }
+ }
+
+ return OK;
+}
+
+PoolStringArray MIDIDriverWinMidi::get_connected_inputs() {
+
+ PoolStringArray list;
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ HMIDIIN midi_in = connected_sources[i];
+ UINT id = 0;
+ MMRESULT res = midiInGetID(midi_in, &id);
+ if (res == MMSYSERR_NOERROR) {
+ MIDIINCAPS caps;
+ res = midiInGetDevCaps(i, &caps, sizeof(MIDIINCAPS));
+ if (res == MMSYSERR_NOERROR) {
+ list.push_back(caps.szPname);
+ }
+ }
+ }
+
+ return list;
+}
+
+void MIDIDriverWinMidi::close() {
+
+ for (int i = 0; i < connected_sources.size(); i++) {
+ HMIDIIN midi_in = connected_sources[i];
+ midiInStop(midi_in);
+ midiInClose(midi_in);
+ }
+ connected_sources.clear();
+}
+
+MIDIDriverWinMidi::MIDIDriverWinMidi() {
+}
+
+MIDIDriverWinMidi::~MIDIDriverWinMidi() {
+
+ close();
+}
+
+#endif
diff --git a/drivers/winmidi/win_midi.h b/drivers/winmidi/win_midi.h
new file mode 100644
index 0000000000..1cf9b19b5d
--- /dev/null
+++ b/drivers/winmidi/win_midi.h
@@ -0,0 +1,61 @@
+/*************************************************************************/
+/* win_midi.h */
+/*************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/*************************************************************************/
+/* Copyright (c) 2007-2018 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2018 Godot Engine contributors (cf. AUTHORS.md) */
+/* */
+/* Permission is hereby granted, free of charge, to any person obtaining */
+/* a copy of this software and associated documentation files (the */
+/* "Software"), to deal in the Software without restriction, including */
+/* without limitation the rights to use, copy, modify, merge, publish, */
+/* distribute, sublicense, and/or sell copies of the Software, and to */
+/* permit persons to whom the Software is furnished to do so, subject to */
+/* the following conditions: */
+/* */
+/* The above copyright notice and this permission notice shall be */
+/* included in all copies or substantial portions of the Software. */
+/* */
+/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
+/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
+/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
+/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
+/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
+/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
+/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
+/*************************************************************************/
+
+#ifdef WINMIDI_ENABLED
+
+#ifndef WIN_MIDI_H
+#define WIN_MIDI_H
+
+#include <stdio.h>
+#include <windows.h>
+
+#include <mmsystem.h>
+
+#include "core/vector.h"
+#include "os/midi_driver.h"
+
+class MIDIDriverWinMidi : public MIDIDriver {
+
+ Vector<HMIDIIN> connected_sources;
+
+ static void CALLBACK read(HMIDIIN hMidiIn, UINT wMsg, DWORD_PTR dwInstance, DWORD_PTR dwParam1, DWORD_PTR dwParam2);
+
+public:
+ virtual Error open();
+ virtual void close();
+
+ virtual PoolStringArray get_connected_inputs();
+
+ MIDIDriverWinMidi();
+ virtual ~MIDIDriverWinMidi();
+};
+
+#endif
+#endif
diff --git a/drivers/xaudio2/audio_driver_xaudio2.cpp b/drivers/xaudio2/audio_driver_xaudio2.cpp
index 6675459313..a1002ef4f9 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.cpp
+++ b/drivers/xaudio2/audio_driver_xaudio2.cpp
@@ -50,7 +50,7 @@ Error AudioDriverXAudio2::init() {
speaker_mode = SPEAKER_MODE_STEREO;
channels = 2;
- int latency = GLOBAL_DEF("audio/output_latency", 25);
+ int latency = GLOBAL_DEF_RST("audio/output_latency", 25);
buffer_size = closest_power_of_2(latency * mix_rate / 1000);
samples_in = memnew_arr(int32_t, buffer_size * channels);
@@ -97,8 +97,6 @@ void AudioDriverXAudio2::thread_func(void *p_udata) {
AudioDriverXAudio2 *ad = (AudioDriverXAudio2 *)p_udata;
- uint64_t usdelay = (ad->buffer_size / float(ad->mix_rate)) * 1000000;
-
while (!ad->exit_thread) {
if (!ad->active) {
diff --git a/drivers/xaudio2/audio_driver_xaudio2.h b/drivers/xaudio2/audio_driver_xaudio2.h
index 42e1adb2b7..0867c56128 100644
--- a/drivers/xaudio2/audio_driver_xaudio2.h
+++ b/drivers/xaudio2/audio_driver_xaudio2.h
@@ -51,7 +51,7 @@ class AudioDriverXAudio2 : public AudioDriver {
HANDLE buffer_end_event;
XAudio2DriverVoiceCallback() :
buffer_end_event(CreateEvent(NULL, FALSE, FALSE, NULL)) {}
- void STDMETHODCALLTYPE OnBufferEnd(void *pBufferContext) { /*print_line("buffer ended");*/
+ void STDMETHODCALLTYPE OnBufferEnd(void *pBufferContext) {
SetEvent(buffer_end_event);
}